python 是否在赋值时复制对象?

Does python copy objects on assignment?

我读到 python 中的赋值并不像在 c 中那样复制它,在 c 中它分配一个指向对象的指针。

但是当我调试这个函数时:

def popall(self):
    objs = self.curstack
    self.curstack = []
    return objs

似乎正在进行某种复制。这个函数运行后obis是满的,self.curstack是空的...

所以正在进行一些复制。是深还是浅?

它不复制任何东西。只是分配给 self.curstack 不会修改 self.curstack 所指的任何内容。它只是让 self.curstack 指向别的东西。

这样想。 self.curstack 指向一些东西。使用 objs = self.curstack 可以使 objs 指向相同的内容。使用 self.curstack = [],您使 self.curstack 指向一个空列表。这不会删除 self.curstack 过去指向的任何内容;那东西还在,objs 还在指着它。

This article 使用标签标记的一个很好的类比来解释它。

Python 在任何地方都使用引用。所以你的代码是这样工作的:

objs = self.curstack

现在 objs 指向 curstack 的任何内容。

self.curstack = []

现在 curstack 指向一个空列表。 objs不变,指向旧的curstack

return objs

你returnobjs,也就是老curstack.

让我们演示一下到底发生了什么(使用显示内存位置的 id

a = [1,2,3]
print id(a)
b = a
print id(b)
a = 4
print id(a)
print a
print b

4339130240

4339130240

4298163184

4

[1, 2, 3]

所以 ab 最初指向内存中的同一个地方,但随后 a 指向新的地方。但是现在,让我们试试

a = [1,2,3]
print id(a)
b = a
print id(b)
a[0] = 4
print id(a)
print a
print b

4339098040

4339098040

4339098040

[4, 2, 3]

[4, 2, 3]

所以 b 不是 a 的全新副本。它与 a 是同一个对象(当它被定义时)。如果你然后做 a=4,你在告诉 python,让我们忘记 a 用来指向什么并赋予它新的含义。 4 没有出现在内存中 a 用来引用 的地方。相反 a 现在指的是内存中的一个新位置。 b 仍然指代 a 最初指代的内容。

如果我们不重新分配 a,而是更改 a 指向的对象中的其中一项,则检查 b 表明发生了相应的更改至 b.

正如所有答案中提到的那样,self.curstack 不会修改它,只是指代某些东西。在你的例子中,它指的是一个空列表 []

您实际上可以使用 swampy

查看对象的引用方式
 from swampy.Lumpy import Lumpy

class ref_test:

    def __init__(self, curstack):
        self.curstack = curstack

    def popall(self): 
        lampy = Lumpy()
        objs = self.curstack 
        self.curstack = [] 
        print id(self.curstack), id(objs)
        lampy.object_diagram()
        return objs

o = ref_test([1,2,3,4])
res = o.popall()
print res

如您所见,self.curstack 指向一个空列表,而 objs 仍然保留 self.curstack 的旧值。

您可以使用id函数来检查对象的“身份”。对于 self.curstackobjs

,这在我们的案例中并不是唯一的
164711692 163838732

在Python中,有两个space,名称space和对象space。

名称只是您分配给对象的标签,这些标签存在于对象 space 中。对象有值和类型;名称只是为了方便我们;这样我们就可以访问对象 space.

中的内容

这与 C 等其他语言不同,在 C 语言中,变量更像是一个盒子,您可以在其中放置某种类型的东西。

在 Python 中,名称可以指向任何类型的任何对象 - 它们只是别名。

当您为对象指定名称时,如下所示:

a = 1

a 只是一个标签,指向具有类型 (int) 和值的对象 1。如果您接下来这样做:

b = 1

现在您有两个名称 ab 指向同一个对象 - 它们不是 "copies",而是指向同一个对象的两个标签。

当你这样做时:

a = 'hello'

现在 a 指向一个新对象,但是 b 仍然指向旧对象 (1)。

最终,当没有名称指向对象时,Python 会进行自动垃圾收集以保持对象 space 优化。