Guo*_*eng 3 python reference cycle
我不确定 python 如何处理循环引用(引用循环)。我检查了一些答案并发现了这个:
Python 的标准引用计数机制无法释放循环,因此示例中的结构会泄漏。
然而,补充垃圾收集工具默认启用,并且应该能够释放该结构,如果它的任何组件都不再可以从外部访问并且它们没有__del__()方法。
我想这意味着如果引用循环中的所有实例都无法在外部访问,则它们都将被清除。这是真的?
另一方面,有一个weakref通常用于处理地图字典的包。我想它存在的目的是为了避免引用循环。
综上所述,python可以自动处理引用循环吗?如果他们可以,为什么我们必须使用weakref?
如果循环中的对象没有自定义__del__方法,则不必担心引用循环,因为 Python 可以(并且将)以任何顺序销毁对象。
如果您的自定义方法确实有一个__del__方法,Python 根本不知道一个对象的删除是否会影响另一个对象的删除。假设当一个对象被删除时,它会设置一些全局变量。所以,物体会粘在周围。作为快速测试,您可以创建一个__del__打印某些内容的方法:
class Deletor(str):
def __del__(self):
print(self, 'has been deleted')
a = Deletor('a') # refcount: 1
del a # refcount: 0
Run Code Online (Sandbox Code Playgroud)
输出:
a has been deleted
Run Code Online (Sandbox Code Playgroud)
但是如果你有这样的代码:
a = Deletor('a') # refcount: 1
a.circular = a # refcount: 2
del a # refcount: 1
Run Code Online (Sandbox Code Playgroud)
它什么都不输出,因为 Python 不能安全地删除a.
对此有两种解决方案。的weakref:
# refcount: a b
a = Deletor('a') # 1 0
b = Deletor('b') # 1 1
b.a = a # 2 1
a.b = weakref.ref(b) # 2 1
del a # 1 1
del b # 1 0
# del b kills b.a # 0 0
Run Code Online (Sandbox Code Playgroud)
输出:
b has been deleted
a has been deleted
Run Code Online (Sandbox Code Playgroud)
(注意如何b先删除再删除a)
您可以手动删除循环(如果您可以跟踪它们):
# refcount a b
a = Deletor('a') # 1 0
b = Deletor('b') # 1 1
b.a = a # 2 1
a.b = b # 2 2
del b # 2 1
print('del b')
del a.b # 2 0
# b is deleted, now dead
# b.a now dead # 1 0
print('del a.b')
del a # 0 0
print('del a')
Run Code Online (Sandbox Code Playgroud)
输出:
del b
b has been deleted
del a.b
a has been deleted
del a
Run Code Online (Sandbox Code Playgroud)
注意b删除后 如何a.b删除。
| 归档时间: |
|
| 查看次数: |
2632 次 |
| 最近记录: |