python “指针“bytearry与memoryveiw

前言

为什么很多编程里都有指针这个东西,python好像没有吧…
是…真的没有指针这个东西吗?
不!但…不完全是…

指针?内存!

在很多语言中指针是指一个变量它指向着另一个变量的地址
简单来说就是有一个变量a,另一个变量b是a的指针,那么b变量的值就是a的内存地址
可是!
在Python里这不是指针,是内存访问!

bytes与bytearray

在说bytearray前我们先说bytes

bytes

它的构造是这样子的

bytes([source[, encoding[, errors]]])
  • sourc(以下摘自Python的文档)
    • 如果是一个 string,您必须提供 encoding 参数(errors 参数仍是可选的);bytes() 会使用str.encode()方法来将 string 转变成 bytes。
    • 如果是一个integer,会初始化大小为该数字的数组,并使用 null 字节填充。
    • 如果是一个遵循缓冲区接口的对象,该对象的只读缓冲区将被用来初始化字节数组。
    • 如果是一个iterable可迭代对象,它的元素的范围必须是0 <= x < 256的整数,它会被用作数组的初始内容。
  • encoding
    • 如果懒得用str.encode()的话,可以直接在这个参数里面写
  • error(不常用)
    • errors(与source和encoding参数一起使用时可能需要):此参数指定了在编码过程中遇到无法编码的字符时的错误处理方式。常见的处理方式包括’strict’(默认值,遇到错误时抛出异常)、‘ignore’(忽略无法编码的字符)、‘replace’(用特定字符替换无法编码的字符)等。如果source不是字符串,或者没有指定encoding参数,则不需要此参数。可以看Python官方文档

bytearray

bytearray([source[, encoding[, errors]]])

bytes的构造是一样的
bytes只读的
bytearray可改的
我们后面在来聊这个东西

memoryview

python里面有一个对象:

memoryview()

这个玩意是可以访问到内存的,和id函数一样
但是他们取得值是一样的

我们可以可以运行一下代码:

a = "hallo world".encode("utf-8")
p = bytearray(a)
'''
上面这两行代码也可以写成这样:
a = "hallo world"
p = bytearray(a,"utf-8")
'''

point = memoryview(p)
print(point) # <memory at 0x...> 其中0x...是一个十六进制数
print(id(point)) # 一个整数
print(eval(str(point.__repr__()).split("at ")[-1][:-1])) # 解析"<memory at "后的十六进制数

我们可以看到这两个数是一样的
什么?你眼力不行?可以用这个代码:print(id(point)==eval(str(point.__repr__()).split("at ")[-1][:-1])),结果是True!(别跟我说True是什么意思


它还支持切片

a = "hallo world"
a = bytearray(a,"utf-8")
point = memoryview(a)
print(point[0]) # 104
print(chr(point[0])) # h

我们也可以修改切片的值
假如修改memoryveiw的值会发现像指针一样把原来的东西修改

a = "hallo world"
a = bytearray(a,"utf-8")
print(a) # bytearray(b'hallo world')
point = memoryview(a)
point[0] = ord("b")
print(a) # bytearray(b'ballo world')

在这里插句嘴:
chr是把一个ASCII码转成一个字符串
ord是把一个字符串转成ASCII码


你说你想知道这个东西原来是什么样子的?前面的bytearray什么什么的不要?可以用decode函数:

bytes.decode(encoding='utf-8', errors='strict')
bytearray.decode(encoding='utf-8', errors='strict')
  • encoding
    • 指编码格式一般用utf-8
  • errors(不常用)
  • 返回值
    • 一个str对象

我们可以把上面的代码改一改:

a = "hallo world"
a = bytearray(a,"utf-8")
print(a)  # bytearray(b'hallo world')
print(a.decode("utf-8")) # hallo world

point = memoryview(a)
point[0] = ord("b")
print(a) # bytearray(b'ballo world')
print(a.decode("utf-8")) # ballo world

再谈bytes和bytearray

我们经常写的b"hallo"前面的b是只读的
你还不信?!看下面的代码就行了

注意

bytesbytearray对象的方法不接受字符串作为其参数,就像字符串的方法不接受bytes对象作为其参数一样。 例如,你必须使用以下写法:

a = "abc"
b = a.replace("a", "f")

和:

a = b"abc"
b = a.replace(b"a", b"f")

可读与只读

我们把上面的代码复制一下

读取

这个是读取的代码

a = "hallo world"
a = bytes(a,"utf-8")
point = memoryview(a)
print(point[0]) # 104
print(chr(point[0])) # h
# -----
a = "hallo world"
a = bytearray(a,"utf-8")
point = memoryview(a)
print(point[0]) # 104
print(chr(point[0])) # h

很显然,两个都不会报错

写入

这个是写入的代码

a = "hallo world"
a = bytearray(a,"utf-8")
point = memoryview(a)
point[0] = ord("b")
print(a) # bytearray(b'ballo world')
print(a.decode("utf-8")) # ballo world
# -----
a = "hallo world"
a = bytes(a,"utf-8")
point = memoryview(a)
point[0] = ord("b") # 报错:TypeError: cannot modify read-only memory
print(a)
print(a.decode("utf-8"))

bytearray是正常的
而bytes报错了,因为它是只读的
这个报错cannot modify read-only memory翻译是无法修改只读存储器

你不是不信我说我写的b"hallo"的b是只读的吗?上代码!

a = b"hallo world"
point = memoryview(a)
point[0]=ord("b") # 报错:TypeError: cannot modify read-only memory
print(a)

现在信我了吧!

关于中文

我们一般用的编码是utf-8,一个中文是由3个字节存储的(就是3个char)
还有以下有一些易错点:

print(b"你") # SyntaxError: bytes can only contain ASCII literal characters.
print(bytes("你")) # TypeError: string argument without an encoding
print(bytes("你","utf-8"))

前两行是因为只可以在ASCII里面的字符,要utf-8解码
我们可以看到最后一行输出的是b'\xe4\xbd\xa0'
所以我们不能直接像前面改字母一样使用point[0] = ord("b")来修改,不然就会解不了码:UnicodeDecodeError: 'utf-8' codec can't decode byte 0x... in position ...: invalid start byte
修改的话可以这样:

point[start:end] = bytes("字","utf-8")

start和end:文字的搜引,记住一个文字算3,一个字母算1,比如"a你好"=>“你"是”[1:4]“,“好"是”[4:]”

后文

啊!..终于写完了!!!
啊?!!晚上了?!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值