Python 对象是如何引用自身的?

Python 对象是如何引用自身的?,python,object,reference,garbage-collection,Python,Object,Reference,Garbage Collection,因为create_cycle()创建一个引用自身的对象x,所以当函数返回时,对象x不会自动被释放。这将导致在调用Python垃圾回收器之前一直保留x使用的内存 有人能解释一下这个物体是如何指它自己的吗?请详细解释上述帖子所说的内容。当您将对象(如列表)分配给变量时,不会复制该对象,而是创建对该对象的引用。你可以把它看作一个指针。例如: def create_cycle(): # create a list x x = [] # A reference cycle

因为create_cycle()创建一个引用自身的对象x,所以当函数返回时,对象x不会自动被释放。这将导致在调用Python垃圾回收器之前一直保留x使用的内存


有人能解释一下这个物体是如何指它自己的吗?请详细解释上述帖子所说的内容。

当您将对象(如列表)分配给变量时,不会复制该对象,而是创建对该对象的引用。你可以把它看作一个指针。例如:

def create_cycle(): 

    # create a list x 

    x = []

    # A reference cycle is created 

    # here as x contains a reference to 

    # to self. 

    x.append(x) 


create_cycle() 
a = []
b = a
这将创建一个空列表,并将对该列表的引用分配给
a
。以下分配创建了对
b
中列表的第二个引用。如果更改列表,例如
a.append(5)
,列表将变为
[5]
。由于
a
b
都引用了该列表,因此它们都具有相同的值

引用也可以来自对象内部,例如列表。例如:

def create_cycle(): 

    # create a list x 

    x = []

    # A reference cycle is created 

    # here as x contains a reference to 

    # to self. 

    x.append(x) 


create_cycle() 
a = []
b = a
这将创建两个列表。第一个是空列表,从
a
引用它。第二个是包含单个元素的列表,它是对
a
的第二个引用。如果再次执行
a.append(5)
,则第一个列表变为
[5]
,第二个列表变为
[[5]]

现在,假设您执行以下操作:

a = []
b = [a]
第一条语句再次创建一个空列表,由
a
引用。然后,第二个通过向列表中添加值来修改该列表。但在本例中,它不是将数字或引用附加到其他列表,而是将引用附加到列表本身。因此,列表最终包含一个元素,它是对列表本身的引用。这是一个循环引用。如果您尝试打印
a
,它将继续不断地深入引用,但Python会检测循环并显示
以指示循环

周期影响Python中的垃圾收集。Python保留每个对象的引用计数。每次创建对对象的新引用时,该对象的引用计数都会增加。删除引用时(例如,通过为引用对象的变量指定不同的值,或通过变量超出范围),引用计数将递减。当它达到零时,Python知道它可以对该对象进行垃圾收集(即释放)。这样做时,它引用的任何对象的引用计数也会减少。通常,整个引用树可以通过这种方式解除分配


但是,如果参考图不是一棵树,即如果它包含一个循环,则这不起作用。例如,可以以相互引用的对象循环结束,每个对象的引用计数为1。要处理此情况,需要标记并清除垃圾收集通行证。这将遍历所有引用以查看哪些是可访问的。然后,它会释放任何无法访问的内容,即使其引用计数非零。

@NirajRaut好吧,它开始时是一个空列表
[]
,分配给
x
。此时,它的引用计数为1。如果函数在该点返回,
x
将超出范围,则引用计数将降至0,并将立即释放。但是,它会将
x
附加到列表中,即列表本身。此时列表不再是
[]
,而是
[x]
,其中
x
是对列表的引用。如果您试图展开它,它将看起来像
[][[][[[…][]]]]
。也就是说,它似乎是一个无限的巢穴。(续)@NirajRaut(续)仍然只有一个列表,但现在引用计数为2:一个来自变量
x
,另一个来自列表本身的第一个(也是唯一的)元素。如果函数现在返回,引用计数将下降到1,列表将成为孤立列表。在Python执行垃圾收集过程之前,内存不会被回收,此时它会检测到列表不可访问并将其释放。@NirajRaut注意,您可以使用涉及多个对象的更复杂的循环引用。例如:
a=[];b=[a];a、 附加(b)
。这会产生两个相互引用的列表:
a
引用的列表引用
b
引用的列表,反之亦然。同样,如果函数返回,两个列表的引用计数都为1,并且在执行垃圾收集过程之前,不会回收存储。@NirajRaut它们基本上是一样的。如果创建了5个列表,则创建了5个列表实例。同样的事情也发生在课堂上。类本身也是一个对象,但通常不会将其称为实例。但每次创建该类的实例时,例如,
x=ClassName(…)
,都创建了一个新实例。@NirajRaut类和类的实例都是对象。“对象”这个词相当宽泛。基本上,一切都是一个对象。“实例”是一个较窄的术语。您不会引用“类的对象”。不过,这已经离主题很远了。您可能会发现一些Python文档更精确地定义了这些术语。