首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么可以使用python 3中的ctype修改不可变字节对象?

为什么可以使用python 3中的ctype修改不可变字节对象?
EN

Stack Overflow用户
提问于 2017-12-02 15:56:46
回答 1查看 1.8K关注 0票数 1

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

代码语言:javascript
复制
>>> 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对象也是不可变的:

代码语言:javascript
复制
>>> bar = "bar"
>>> bar[0] = "#"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

可以用ctype修改字节对象,而对str对象则不可能这样做。你能解释一下为什么吗?请看下面的例子。

c代码

代码语言:javascript
复制
char* foo(char *bar) {
    bar[0] = '#';
    return bar;
}

c #代码编译

代码语言:javascript
复制
gcc -shared -o clib.so -fPIC clib.c

字节尝试

python代码

代码语言:javascript
复制
import ctypes

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

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

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

python代码输出

代码语言:javascript
复制
Before: b'bar' 140451244811328
After:  b'#ar' 140451244811328

str企图

str对象在Python 3中也是不可变的,但是与字节对象不同,不可能用ctype修改它。

python代码

代码语言:javascript
复制
import ctypes

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

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

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

python代码输出

代码语言:javascript
复制
Before: bar 140385853714080
After:  bar 140385853714080
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-12-02 17:56:50

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

bytes情况下,ctypes传递指向其字节内部缓冲区的指针,但并不期望对其进行修改。考虑:

代码语言:javascript
复制
a = b'123'
b = b'123'

由于bytes是不可变的,所以Python可以在ab中存储相同的引用。如果将b传递给ctypes-wrapped函数并对其进行修改,它也可能破坏a

直接从ctypes文档

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

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47609698

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档