将另一个变量分配给字符串是否会复制或增加引用计数

时间:2012-07-20 19:35:20

标签: python

在David Beazley的“Python基本参考”第35页中,他首先声明:

  

对于诸如字符串之类的不可变数据,积极地使用解释器   在程序的不同部分之间共享对象。

然而,稍后在同一页上,他说

  

对于诸如数字和字符串之类的不可变对象,这个赋值   有效地制作副本。

但这不是一个矛盾吗?一方面,他说他们是共享的,但后来他说他们被复制了。

3 个答案:

答案 0 :(得分:10)

python中的赋值永远不会创建副本(只有在通过使用__setattr__,属性或描述符重新定义类成员的赋值时,技术上才可行。)

所以

之后
a = foo()
b = a

foo返回的任何内容都没有被复制,而是有两个变量ab指向同一个对象。无论对象是否是不可变的。

对于不可变对象,但是很难判断是否是这种情况(因为你不能使用一个变量来改变对象并检查使用另一个变量是否可见)所以你可以自由地认为a并且b不能相互影响。

对于某些不可变对象,Python可以自由地重用旧对象,而不是在

之后创建新对象
a = x + y
b = x + y

其中xy都是数字(因此总和是一个数字并且是不可变的)可能是ab都指向同一个数字宾语。请注意,没有这样的保证......也可能是它们将指向具有相同值的不同对象。

要记住的重要一点是,除非特别指示使用例如Python,否则Python永远不会复制。 copydeepcopy。对于可变对象,这是非常重要,以避免意外。

您可以看到的一个常见习语是:

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

str1str2 具有相同的值:

>>> str1
'ATG'
>>> str2
'ATG'

这是因为 str1str2 都指向同一个对象,事实证明它们共享相同的唯一对象 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 变量分配给另一个变量名称不会在内存中创建其值的副本