在David Beazley的“Python基本参考”第35页中,他首先声明:
对于诸如字符串之类的不可变数据,积极地使用解释器 在程序的不同部分之间共享对象。
然而,稍后在同一页上,他说
对于诸如数字和字符串之类的不可变对象,这个赋值 有效地制作副本。
但这不是一个矛盾吗?一方面,他说他们是共享的,但后来他说他们被复制了。
答案 0 :(得分:10)
python中的赋值永远不会创建副本(只有在通过使用__setattr__
,属性或描述符重新定义类成员的赋值时,技术上才可行。)
所以
之后a = foo()
b = a
从foo
返回的任何内容都没有被复制,而是有两个变量a
和b
指向同一个对象。无论对象是否是不可变的。
对于不可变对象,但是很难判断是否是这种情况(因为你不能使用一个变量来改变对象并检查使用另一个变量是否可见)所以你可以自由地认为a
并且b
不能相互影响。
对于某些不可变对象,Python可以自由地重用旧对象,而不是在
之后创建新对象a = x + y
b = x + y
其中x
和y
都是数字(因此总和是一个数字并且是不可变的)可能是a
和b
都指向同一个数字宾语。请注意,没有这样的保证......也可能是它们将指向具有相同值的不同对象。
要记住的重要一点是,除非特别指示使用例如Python,否则Python永远不会复制。 copy
或deepcopy
。对于可变对象,这是非常重要,以避免意外。
您可以看到的一个常见习语是:
class Polygon:
def __init__(self, pts):
self.pts = pts[:]
...
在这种情况下,使用self.pts = pts[:]
代替self.pts = pts
制作整个点数组的副本,以确保在创建对象更改后应用于点列表不会意外更改传递给构造函数的列表。
答案 1 :(得分:5)
有效地创建副本。它实际上创建副本。拥有两个副本和两个名称共享相同值的主要区别在于,在后一种情况下,通过一个名称进行的修改会影响另一个名称的值。如果该值不能被改变,则该差异消失,因此对于不可变对象,该值是否被复制几乎没有实际后果。
在某些极端情况下,即使对于不可变类型,您也可以区分副本和不同对象之间的区别(例如,通过使用id
函数或is
运算符),但这些无效对于Python内置不可变类型(如字符串和数字)。
答案 2 :(得分:0)
否,将预先存在的 str
变量分配给新的变量名称不会在内存中创建该值的独立副本。
可以使用 id()
函数检查内存中是否存在唯一对象。例如,使用交互式 Python 提示,尝试:
>>> str1 = 'ATG'
>>> str2 = str1
str1
和 str2
具有相同的值:
>>> str1
'ATG'
>>> str2
'ATG'
这是因为 str1
和 str2
都指向同一个对象,事实证明它们共享相同的唯一对象 ID:
>>> id(str1)
140439014052080
>>> id(str2)
140439014052080
>>> id(str1) == id(str2)
True
现在假设您修改了 str1
:
>>> str1 += 'TAG' # same as str1 = str1 + 'TAG'
>>> str1
ATGTAG
因为 str
对象是不可变的,所以上面的赋值创建了一个具有自己 ID 的新的唯一对象:
>>> id(str1)
140439016777456
>>> id(str1) == id(str2)
False
然而,str2
保持与之前相同的 ID:
>>> id(str2)
140439014052080
因此,str1 += 'TAG'
的执行将一个全新的 str
对象及其自己的唯一 ID 分配给变量 str1
,而 str2
继续指向原始 {{ 1}} 对象。
这意味着将现有的 str
变量分配给另一个变量名称不会在内存中创建其值的副本。