python classes 和 class 属性何时被垃圾收集?
When are python classes and class attributes garbage collected?
class Member(object):
def __init__(self, identifier):
self.identifier = identifier
print "Member __init__", self.identifier
def __del__(self):
print "Member __del__", self.identifier
with open("/home/might/" + self.identifier, "w") as outF:
outF.write(self.identifier)
class WithMembers(object):
def __init__(self):
print "WithMembers __init__"
print WithMembers.classMem
self.instanceMem = Member("instance mem")
def __del__(self):
print "WithMembers __del__"
classMem = Member("class mem")
if __name__ == "__main__":
print "main"
WithMembers()
#del WithMembers.classMem # "Member __del__ class mem" before "end"
#del WithMembers # "Member __del__ class mem" after "end"
print "end"
以上代码在 Hidden.py 和 运行 python Hidden.py
中产生以下输出:
Member __init__ class mem
main
WithMembers __init__
<__main__.Member object at 0x935aeec>
Member __init__ instance mem
WithMembers __del__
Member __del__ instance mem
end
我没有在输出或 class mem
文件中看到 Member __del__ class mem
,除非我取消注释其中一个 del
语句。为什么是这样? python classes 和 class 属性何时被垃圾收集?
classMem
是 class WithMembers
的 class 变量,这意味着它将被此 class 的所有实例共享。在 Python 中这是一个全球性的事情。
这就是 class 的 __del__
成员在退出程序时没有被调用的原因。
这里有一个问题:为什么Python在退出程序时不简单地将所有引用计数设置为0,以便所有__del__
函数都被调用?
像C++一样,保证调用全局变量的析构函数。在 Python 中保证这一点的唯一方法是 运行 遍历所有模块并删除它们的所有变量。但这意味着 __del__
方法不能相信它可能想要使用的任何全局变量仍然存在,因为无法知道要删除变量的顺序。
有两种方法可以强制销毁classMem
。
一个是del WithMembers.classMem
。这将减少对 0 的引用计数,并且 __del__
将被自动调用。
另一个是使 class WithMembers
成为旧式 class(不是继承自 object
)。像这样:
...
class WithMembers:
def __init__(self):
print "WithMembers __init__"
print WithMembers.classMem
self.instanceMem = Member("instance mem")
...
输出将是:
Member __init__ class mem
main
WithMembers __init__
<__main__.Member object at 0x00000000026C5278>
Member __init__ instance mem
WithMembers __del__
Member __del__ instance mem
end
Member __del__ class mem
这里有一个非常有用的 link 可以帮助您更好地理解这个答案。
http://www.electricmonk.nl/log/2008/07/07/python-destructor-and-garbage-collection-notes/
希望对您有所帮助。 :)
这被报告为 http://bugs.python.org/issue1545463 fixed in 3.4 but not backported (I was running 2.7). This was also explained in http://code.activestate.com/lists/python-list/504216/ 中的错误。 python 3.5.
中的输出见下文
基于以上,我的理解是在 2.7 中,当解释器退出时,新样式 class WithMembers
仍然存在(未被 GC 清理)。结果,classMem
没有被垃圾回收,因为 WithMembers
仍然引用它。
注意新样式 classes 具有来自 __mro__
和一些内置描述符 (http://bugs.python.org/issue17950) 的对自身的循环引用。尽管模块级新样式 classes 在模块清理后被 GC 认为已死,但在模块清理后调用清理它们的 GC 被禁用,因为它导致了太多其他问题。
这不会导致内存泄漏,因为 OS 会在解释器退出后清理资源。
class Member(object):
def __init__(self, identifier):
self.identifier = identifier
print("Member __init__ " + self.identifier)
def __del__(self):
print("Member __del__ " + self.identifier)
with open("/home/might/" + self.identifier, "w") as outF:
outF.write(self.identifier)
class WithMembers(object):
def __init__(self):
print("WithMembers __init__")
print(WithMembers.classMem)
self.instanceMem = Member("instance mem")
def __del__(self):
print("WithMembers __del__")
classMem = Member("class mem")
if __name__ == "__main__":
print("main")
WithMembers()
print("end")
当 运行 和 python3 Hidden.py
时输出以下内容:
Member __init__ class mem
main
WithMembers __init__
<__main__.Member object at 0xb6fc8e2c>
Member __init__ instance mem
WithMembers __del__
Member __del__ instance mem
end
Member __del__ class mem
Exception ignored in: <bound method Member.__del__ of <__main__.Member object at 0xb6fc8e2c>>
Traceback (most recent call last):
File "class_member_gc.py", line 8, in __del__
NameError: name 'open' is not defined
class Member(object):
def __init__(self, identifier):
self.identifier = identifier
print "Member __init__", self.identifier
def __del__(self):
print "Member __del__", self.identifier
with open("/home/might/" + self.identifier, "w") as outF:
outF.write(self.identifier)
class WithMembers(object):
def __init__(self):
print "WithMembers __init__"
print WithMembers.classMem
self.instanceMem = Member("instance mem")
def __del__(self):
print "WithMembers __del__"
classMem = Member("class mem")
if __name__ == "__main__":
print "main"
WithMembers()
#del WithMembers.classMem # "Member __del__ class mem" before "end"
#del WithMembers # "Member __del__ class mem" after "end"
print "end"
以上代码在 Hidden.py 和 运行 python Hidden.py
中产生以下输出:
Member __init__ class mem
main
WithMembers __init__
<__main__.Member object at 0x935aeec>
Member __init__ instance mem
WithMembers __del__
Member __del__ instance mem
end
我没有在输出或 class mem
文件中看到 Member __del__ class mem
,除非我取消注释其中一个 del
语句。为什么是这样? python classes 和 class 属性何时被垃圾收集?
classMem
是 class WithMembers
的 class 变量,这意味着它将被此 class 的所有实例共享。在 Python 中这是一个全球性的事情。
这就是 class 的 __del__
成员在退出程序时没有被调用的原因。
这里有一个问题:为什么Python在退出程序时不简单地将所有引用计数设置为0,以便所有__del__
函数都被调用?
像C++一样,保证调用全局变量的析构函数。在 Python 中保证这一点的唯一方法是 运行 遍历所有模块并删除它们的所有变量。但这意味着 __del__
方法不能相信它可能想要使用的任何全局变量仍然存在,因为无法知道要删除变量的顺序。
有两种方法可以强制销毁classMem
。
一个是del WithMembers.classMem
。这将减少对 0 的引用计数,并且 __del__
将被自动调用。
另一个是使 class WithMembers
成为旧式 class(不是继承自 object
)。像这样:
...
class WithMembers:
def __init__(self):
print "WithMembers __init__"
print WithMembers.classMem
self.instanceMem = Member("instance mem")
...
输出将是:
Member __init__ class mem
main
WithMembers __init__
<__main__.Member object at 0x00000000026C5278>
Member __init__ instance mem
WithMembers __del__
Member __del__ instance mem
end
Member __del__ class mem
这里有一个非常有用的 link 可以帮助您更好地理解这个答案。 http://www.electricmonk.nl/log/2008/07/07/python-destructor-and-garbage-collection-notes/
希望对您有所帮助。 :)
这被报告为 http://bugs.python.org/issue1545463 fixed in 3.4 but not backported (I was running 2.7). This was also explained in http://code.activestate.com/lists/python-list/504216/ 中的错误。 python 3.5.
中的输出见下文基于以上,我的理解是在 2.7 中,当解释器退出时,新样式 class WithMembers
仍然存在(未被 GC 清理)。结果,classMem
没有被垃圾回收,因为 WithMembers
仍然引用它。
注意新样式 classes 具有来自 __mro__
和一些内置描述符 (http://bugs.python.org/issue17950) 的对自身的循环引用。尽管模块级新样式 classes 在模块清理后被 GC 认为已死,但在模块清理后调用清理它们的 GC 被禁用,因为它导致了太多其他问题。
这不会导致内存泄漏,因为 OS 会在解释器退出后清理资源。
class Member(object):
def __init__(self, identifier):
self.identifier = identifier
print("Member __init__ " + self.identifier)
def __del__(self):
print("Member __del__ " + self.identifier)
with open("/home/might/" + self.identifier, "w") as outF:
outF.write(self.identifier)
class WithMembers(object):
def __init__(self):
print("WithMembers __init__")
print(WithMembers.classMem)
self.instanceMem = Member("instance mem")
def __del__(self):
print("WithMembers __del__")
classMem = Member("class mem")
if __name__ == "__main__":
print("main")
WithMembers()
print("end")
当 运行 和 python3 Hidden.py
时输出以下内容:
Member __init__ class mem
main
WithMembers __init__
<__main__.Member object at 0xb6fc8e2c>
Member __init__ instance mem
WithMembers __del__
Member __del__ instance mem
end
Member __del__ class mem
Exception ignored in: <bound method Member.__del__ of <__main__.Member object at 0xb6fc8e2c>>
Traceback (most recent call last):
File "class_member_gc.py", line 8, in __del__
NameError: name 'open' is not defined