我asked to show how为一个特殊记录器的旧栗子做单独解决方案。在努力指出不做这种事情的原因时,我仍然尝试过。
这样做,我有一个静态类成员意外消失。
使用此类声明:
epiLogger.py:
import logging
class epiLogger():
_initialised = {}
_finalised = {}
def __init__(self, name):
self.logger = logging.getLogger(name)
self.name = name
if not epiLogger._initialised.get(name):
self.logger.addHandler(logging.StreamHandler())
self.logger.setLevel(logging.INFO)
self.logger.info('** My Prologue **')
epiLogger._initialised[self.name] = True
def info(self, the_info):
self.logger.info(the_info)
print epiLogger._finalised.get(self.name)
def __del__(self):
print "destructing", self.name
if not epiLogger._finalised.get(self.name):
print "first destruction"
self.logger.info('** My Epilogue **')
epiLogger._finalised[self.name] = True
这些测试文件:
bar.py:
from epiLogger import *
a = epiLogger("bar")
a.info("foo!")
a.info("bar!")
a.info("party!")
test.py:
import bar
我得到了
~ mgregory$ python test.py
** My Prologue **
foo!
None
bar!
None
party!
None
destructing bar
Exception AttributeError: "'NoneType' object has no attribute '_finalised'" in <bound method epiLogger.__del__ of <epiLogger.epiLogger instance at 0x1004a48c0>> ignored
~ mgregory$
但如果我只运行bar.py文件:
~ mgregory$ python bar.py
** My Prologue **
foo!
None
bar!
None
party!
None
destructing bar
first destruction
** My Epilogue **
~ mgregory$
似乎一个间接层导致对类本身的引用(访问类变量)变为“无”。
我尝试了一个更简单的测试用例,它不会以这种方式失败(!)
frob.py:
class frob():
_nasty_global_thingy = True
def __init__(self):
print "initialising a foo", frob._nasty_global_thingy
def __del__(self):
print "destroying a foo", frob._nasty_global_thingy
bar.py:
from frob import *
a = frob()
print a
导入bar.py时,这不会以同样的方式失败。
我知道这是不尝试此类事情的众多理由之一,但我想了解发生了什么。
答案 0 :(得分:2)
模块全局变量在Python出口处被清除,并且在__del__
挂钩运行时,您的类引用已经消失。
不要指望全球仍在那里。相反,使用type(self)
来获取类引用:
def __del__(self):
print "destructing", self.name
cls = type(self)
if not cls._finalised.get(self.name):
print "first destruction"
self.logger.info('** My Epilogue **')
cls._finalised[self.name] = True
这在object.__del__
hook documentation的警告部分中有记录:
此外,当响应于被删除的模块而调用
__del__()
时(例如,当完成程序的执行时),__del__()
方法引用的其他全局变量可能已被删除或在被拆除的过程(例如进口机械关闭)。因此,__del__()
方法应该保持维持外部不变量所需的绝对最小值。
考虑到模块全局变量是在字典中维护的,因此清除它们的顺序取决于清除时字典的当前依赖于实现和Python版本的顺序。