为什么在Python3中可以使用ctypes修改不可变字节对象?

为什么在Python3中可以使用ctypes修改不可变字节对象?,python,c,python-3.x,ctypes,Python,C,Python 3.x,Ctypes,字节对象是。它不支持项目分配: >>> 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 c代码编译 gcc -shared -o clib.so -fPIC c

字节对象是。它不支持项目分配:

>>> 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
c代码编译

gcc -shared -o clib.so -fPIC clib.c
字节尝试 python代码

char* foo(char *bar) {
    bar[0] = '#';
    return bar;
}
import ctypes

clib = ctypes.CDLL('./clib.so')

bar = b"bar"
print("Before:", bar, id(bar))

clib.foo(bar)
print("After: ", bar, id(bar))
import ctypes

clib = ctypes.CDLL('./clib.so')

bar = "bar"
print("Before:", bar, id(bar))

clib.foo(bar)
print("After: ", bar, id(bar))
python代码输出

Before: b'bar' 140451244811328
After:  b'#ar' 140451244811328
Before: bar 140385853714080
After:  bar 140385853714080
str尝试 str对象在python3中也是不可变的,但与bytes对象不同,不能用ctypes修改它

python代码

char* foo(char *bar) {
    bar[0] = '#';
    return bar;
}
import ctypes

clib = ctypes.CDLL('./clib.so')

bar = b"bar"
print("Before:", bar, id(bar))

clib.foo(bar)
print("After: ", bar, id(bar))
import ctypes

clib = ctypes.CDLL('./clib.so')

bar = "bar"
print("Before:", bar, id(bar))

clib.foo(bar)
print("After: ", bar, id(bar))
python代码输出

Before: b'bar' 140451244811328
After:  b'#ar' 140451244811328
Before: bar 140385853714080
After:  bar 140385853714080

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

bytes
案例中
ctypes
传递一个指向其内部字节缓冲区的指针,但不希望对其进行修改。考虑:

a = b'123'
b = b'123'
由于
字节
是不可变的,因此Python可以自由地在
a
b
中存储相同的引用。如果将
b
传递给
ctypes
包装函数并对其进行修改,则该函数也可能损坏
a

直截了当地说:

但是,您应该小心,不要将[不可变对象]传递给期望指向可变内存的指针的函数。如果您需要可变内存块,ctypes有一个
create\u string\u buffer()
函数,它以各种方式创建这些块


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

bytes
案例中
ctypes
传递一个指向其内部字节缓冲区的指针,但不希望对其进行修改。考虑:

a = b'123'
b = b'123'
由于
字节
是不可变的,因此Python可以自由地在
a
b
中存储相同的引用。如果将
b
传递给
ctypes
包装函数并对其进行修改,则该函数也可能损坏
a

直截了当地说:

但是,您应该小心,不要将[不可变对象]传递给期望指向可变内存的指针的函数。如果您需要可变内存块,ctypes有一个
create\u string\u buffer()
函数,它以各种方式创建这些块


你是在幕后进行的,所以基本上任何事情都是可能的。好吧,我可以接受这一点,但为什么str对象不可能做同样的事情?你能展示你的字符串尝试的代码吗?它出现在“str trunt”标题下-我对我的问题做了一些修改,使它更容易阅读。你是在幕后进行的,所以基本上任何事情都是可能的。好吧,我可以接受这一点,但为什么str对象不可能做到同样的事情呢?你能展示你的字符串尝试的代码吗?它出现在“str true”标题下面-我对我的问题做了一些修改,使它更容易阅读。