copy.copy()
和 copy.deepcopy()
只是复制不可变对象(如元组)的引用。
如何在不同的内存位置创建第一个不可变对象的重复副本?
您正在寻找
deepcopy
。
from copy import deepcopy
tup = (1, 2, 3, 4, 5)
put = deepcopy(tup)
不可否认,这两个元组的ID将指向同一个地址。因为元组是不可变的,所以实际上没有理由创建它的另一个完全相同的副本。但是,请注意,元组可以包含可变元素,并且 deepcopy/id 的行为正如您预期的那样:
from copy import deepcopy
tup = (1, 2, [])
put = deepcopy(tup)
tup[2].append('hello')
print tup # (1, 2, ['hello'])
print put # (1, 2, [])
向其中添加空元组:
>>> a = (1, 2, 3)
>>> a is a+tuple()
False
连接元组总是返回一个新的不同元组,即使结果相等。
试试这个:
tup = (1,2,3)
nt = tuple(list(tup))
这个答案:
这个答案不应该以任何方式在生产代码中使用。现在与 警告/免责声明让我们开始吧。
首先,我要迂腐地回答你的问题。 (我很抱歉,但是学究 我内心无法自拔)。让我们从这个想法开始 不变性。在 cPython 中,没有什么是不可变的。这是因为cPython 让您可以访问一个名为
ctypes
的方便的 lil' 模块。这可以让你
做各种很酷的事情,例如修改 tuple
:
>>> from ctypes import py_object as PyObject_p
>>> mutator = PyObject_p.from_address
>>> victim = (0, 1, 2, 3, 4)
>>> print(victim)
(0, 1, 2, 3, 4)
>>> mutator(id(victim) + 40).value = "not so immutable now, are ye'?"
>>> print(victim)
(0, 1, "not so immutable now, are ye'?", 3, 4)
即使没有
ctypes
,人们总是可以在某些东西中编写扩展模块
像C一样完成同样的事情。然后总是有能力
直接写入进程内存(因为/proc/self/mem
存在),
你可以使用普通的 Python 来做到这一点(没有 ctypes
或扩展模块或
任何这样的东西)。所有这一切都表明,不变性并不真实。什么时候
在 Python 中,某些东西是“不可变的”,这意味着它将成为
如果你想变异的话有点不方便。
像往常一样,处理 Python 的愚蠢的不变性和 安全就是忽略它们。
from ctypes import (
byref as _addrof,
sizeof as _sizeof,
create_string_buffer as _malloc,
cast,
memmove as memcpy,
c_void_p as void_p,
py_object as PyObject_p,
)
# get the base class, since it's not publicly exposed
_ctypes_base_cls = void_p
while (_next_base := _ctypes_base_cls.__bases__[0]) is not object:
_ctypes_base_cls = _next_base
## some utility functions that work with PyObjects as well as ctypes objects
# sizeof
def sizeof(obj):
if isinstance(obj, _ctypes_base_cls):
return _sizeof(obj)
else:
return obj.__sizeof__()
# does the same thing as `&obj` in C
def addrof(obj):
if not isinstance(obj, _ctypes_base_cls):
return void_p(id(obj))
return cast(_addrof(obj), void_p)
# allocate memory
def malloc(size):
return cast(_malloc(size), void_p)
# treat something as a `PyObject *`
def as_pyobj_p(obj):
if not isinstance(obj, _ctypes_base_cls):
what = addrof(obj)
return PyObject_p.from_address(addrof(obj).value)
## now for the magic...
# returns a (shallow) copy of the object
def copyobj(obj):
copy_addr = malloc(sizeof(obj))
memcpy(copy_addr, addrof(obj), sizeof(obj))
return as_pyobj_p(copy_addr).value
orig = (0, 1, 2, 3, 4)
copy = copyobj(orig)
# Show the details of the objects:
print(f"""
original:
{orig!r}
{sizeof(orig)} bytes at address {hex(addrof(orig).value)}
copy:
{copy!r}
{sizeof(copy)} bytes at address {hex(addrof(copy).value)}
{orig is copy = }
""")
这只是一个浅拷贝,但可以用它构建一个真正的深拷贝。 (我说“真实”是因为Python的deepcopy不是真实的:它不复制所谓的 不可变对象,或者对象的类型信息(中的
ob_type
成员)
PyObject
结构),以及其他一些类似的东西。)
享受吧!
较新的 python 版本不会轻易被欺骗。然而,切片与 splat 运算符相结合为您提供了一条出路。使用 Python v3.12 进行测试。
>>> test = (558, 3, 4, 64)
>>> test2 = (558, *test[1:])
>>> test == test2
True
>>> test is test2
False
>>> id(test), id(test2)
(4345565632, 4345564832)
如果您想复制元组,请尝试
tup = ('a',2,obj)
dup_tup = tuple(tup)
在本例中,我们创建了一个新元组:我们可以更改它而不更改第一个元组。
如果我们在这种情况下使用
sec_tup = tup
,我们有两个元组,但更改一个元组也会在另一个元组中完成