为什么在Python 3中可以使用ctypes修改不可变的bytes对象?

2024-05-19 20:54:31 发布

您现在位置:Python中文网/ 问答频道 /正文

字节对象是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对象也是不可变的:

^{pr2}$

可以用ctypes修改bytes对象,而不能用str对象修改bytes对象。你能解释一下为什么吗?请看下面的例子。在

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对象在python3中也是不可变的,但与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

Tags: 对象代码id字节bytessofoobar
1条回答
网友
1楼 · 发布于 2024-05-19 20:54:31

python3中的str抽象为Unicode,根据字符串中使用的最高Unicode字符,可以将其存储为每个字符串1、2或4字节。要将字符串传递给C函数,必须将其转换为特定的表示形式。ctypes在本例中,将转换后的临时缓冲区传递给C而不是原始缓冲区。ctypes如果函数原型不正确,或者将不可变对象发送给改变内容的函数,那么Python可能会崩溃和损坏,在这种情况下,用户需要小心。在

bytes的情况下,ctypes会传递一个指向其内部字节缓冲区的指针,但并不期望它被修改。考虑:

a = b'123'
b = b'123'

由于bytes是不可变的,Python可以在a和{}中存储相同的引用。如果您将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....

相关问题 更多 >