首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如果元组在设计上是不可变的,那么为什么cpython将'PyTuple_SetItem‘公开为C呢?

如果元组在设计上是不可变的,那么为什么cpython将'PyTuple_SetItem‘公开为C呢?
EN

Stack Overflow用户
提问于 2022-11-11 16:03:49
回答 2查看 427关注 0票数 10

python中的元组在设计上是不可变的,所以如果我们尝试改变一个Tuple对象,python就会发出下面的TypeError,这是有意义的。

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

因此,我的问题是,如果元组在设计上是不可变的,为什么cpython将PyTuple_SetItem公开为C?

从它描述的文档中

int PyTuple_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o)o指向的元组的位置插入对对象p的引用。成功后返回0。如果pos超出界限,返回-1并设置IndexError异常。

这个语句不完全等于python层中的tuple[index] = value吗?如果目标是从项目集合中创建一个元组,我们可以使用PyTuple_Pack

补充说明:

经过多次使用ctypes.pythonapi的尝试和错误之后,我成功地使用PyTuple_SetItem修改了元组对象。

代码语言:javascript
复制
import ctypes

from ctypes import py_object

my_tuple = (1, 2, 3)
newObj = py_object(my_tuple)

m = "hello"

# I don't know why I need to Py_DecRef here. 
# Although to reproduce this in your system,  no of times you have 
# to do `Py_DecRef` depends on no of ref count of `newObj` in your system
ctypes.pythonapi.Py_DecRef(newObj)
ctypes.pythonapi.Py_DecRef(newObj)
ctypes.pythonapi.Py_DecRef(newObj)

ctypes.pythonapi.Py_IncRef(m)



PyTuple_SetItem = ctypes.pythonapi.PyTuple_SetItem
PyTuple_SetItem.argtypes = ctypes.py_object, ctypes.c_size_t, ctypes.py_object

PyTuple_SetItem(newObj, 0, m)
print(my_tuple) # this will print `('hello', 2, 3)`
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-11-11 16:34:17

类似地,有一个带有警告的PyTuple_Resize函数

因为元组应该是不可变的,所以只有在只有一个对对象的引用时才应该使用元组。如果代码的其他部分可能已经知道元组,请不要使用此方法。元组在结束时总是会生长或收缩。把这想成是摧毁旧的元组,创建一个新的元组,只是效率更高。

从源代码来看,函数上有一个保护程序。

代码语言:javascript
复制
if (!PyTuple_Check(op) || Py_REFCNT(op) != 1) {
    .... error ....

当然,这是允许的,只有当只有一个引用元组-那个引用是一个东西,认为是一个好主意来改变它。因此,元组“基本上是不可变的”,但是C代码可以在有限的情况下更改它,以避免创建新元组的代价。

票数 10
EN

Stack Overflow用户

发布于 2022-11-11 16:38:12

有一个文件中的说明说:

注意,此函数“窃取”对o的引用,并在受影响的位置丢弃对元组中已经存在的项的引用。

否则,在Cpython Github博士中,我们可以看到关于这个函数的更多细节,特别是这个函数如何以及为什么steals对象引用。我们可以读到:

顺便提一句,:c:func:PyTuple_SetItem是设置元组项的唯一方法;:c:func:PySequence_SetItem和:c:func:PyObject_SetItem拒绝这样做,因为元组是不可变的数据类型。您应该只对自己创建的元组使用:c:func:PyTuple_SetItem。 可以使用:c:func:PyList_New和:c:func:PyList_SetItem编写用于填充列表的等效代码。 然而,在实践中,您很少使用这些创建和填充元组或列表的方法。有一个通用函数:c:func:Py_BuildValue,它可以从C值创建最常见的对象,由a :dfn:format string指导。

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

https://stackoverflow.com/questions/74405180

复制
相关文章

相似问题

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