bytes对象是immutable。它不支持项目分配:
>>> bar = b"bar"
>>> bar[0] = b"#"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'bytes' object does not support item assignment
str对象也是不可变的:
>>> bar = "bar"
>>> bar[0] = "#"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
可以使用ctypes修改字节对象,而不能对str对象执行相同操作。你能解释一下原因吗?请看下面的例子。
c code
char* foo(char *bar) {
bar[0] = '#';
return bar;
}
c代码编译
gcc -shared -o clib.so -fPIC clib.c
python代码
import ctypes
clib = ctypes.CDLL('./clib.so')
bar = b"bar"
print("Before:", bar, id(bar))
clib.foo(bar)
print("After: ", bar, id(bar))
python代码输出
Before: b'bar' 140451244811328
After: b'#ar' 140451244811328
str对象在Python 3中也是不可变的,但与字节对象不同,它不可能用ctypes修改它。
python代码
import ctypes
clib = ctypes.CDLL('./clib.so')
bar = "bar"
print("Before:", bar, id(bar))
clib.foo(bar)
print("After: ", bar, id(bar))
python代码输出
Before: bar 140385853714080
After: bar 140385853714080
答案 0 :(得分:4)
str
被抽象为Unicode,并且每个字符串可以存储为1个,2个或4个字节,具体取决于字符串中使用的最高Unicode字符。要将字符串传递给C函数,必须将其转换为特定的表示形式。在这种情况下,ctypes
将转换后的临时缓冲区传递给C而不是原始缓冲区。如果您错误地设计函数或将不可变对象发送到改变内容的函数,ctypes
可能会崩溃并破坏Python,并且在这些情况下由用户注意。
在bytes
情况下ctypes
传递指向其内部缓冲区的指针,但不希望它被修改。考虑:
a = b'123'
b = b'123'
由于bytes
是不可变的,因此Python可以在a
和b
中自由存储相同的引用。如果您将b
传递给ctypes
- 包裹的函数并对其进行修改,则可能会损坏a
。
直接来自ctypes documentation:
但是,您应该小心,不要将[immutable objects]传递给期望指向可变内存的函数。如果你需要可变的内存块,ctypes有一个
create_string_buffer()
函数可以用各种方式创建它们....