字节对象是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 修改 bytes 对象,而不能用 str 对象做同样的事情。你能解释一下为什么吗?请查看以下示例。
c 代码
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 尝试
str 对象在 Python 3 中也是不可变的,但与 bytes 对象不同,它不能用 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
最佳答案
Python 3 中的
str
被抽象为 Unicode,并且可以存储为每个字符串 1、2 或 4 字节,具体取决于字符串中使用的最高 Unicode 字符。要将字符串传递给 C 函数,必须将其转换为特定的表示形式。 ctypes
在这种情况下将转换后的临时缓冲区传递给 C 而不是原始缓冲区。 ctypes
可能会崩溃并损坏 Python,如果您对函数进行原型(prototype)设计不正确或将不可变对象(immutable对象)发送到会改变内容的函数,在这些情况下用户需要小心。
在bytes
的情况下,ctypes
传递一个指向其内部字节缓冲区的指针,但不希望它被修改。考虑:
a = b'123'
b = b'123'
由于 bytes
是不可变的,Python 可以自由地在 a
和 b
中存储相同的引用。如果您将 b
传递给一个 ctypes
包装的函数并且它对其进行了修改,它也可能会损坏 a
。
直接来自 ctypes documentation :
You should be careful, however, not to pass [immutable objects] to functions expecting pointers to mutable memory. If you need mutable memory blocks, ctypes has a
create_string_buffer()
function which creates these in various ways....
关于python - 为什么可以在 python 3 中使用 ctypes 修改不可变字节对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47609698/