静态类成员/类引用的生命周期? [英] Lifetime of static class members/class references?
问题描述
我要求展示如何为特殊记录器的旧栗子做类似单例的解决方案。我仍然不遗余力地指出不做这种事情的原因。
I was asked to show how to do a singleton like solution for the old chestnut of a special logger. At pains to point out the reasons for not doing this sort of thing, still, I tried.
这样做,我有一个静态的类成员意外消失了。
In doing so, I have a static class member disappearing unexpectedly.
使用此类声明:
epiLogger.py:
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文件:
But if I run just the bar.py file:
~ mgregory$ python bar.py
** My Prologue **
foo!
None
bar!
None
party!
None
destructing bar
first destruction
** My Epilogue **
~ mgregory$
似乎一个间接级别导致对类本身的引用(访问类变量)已变为无。
It seems that one level of indirection has resulted in the reference to the class itself (to access the class variable) has become "None".
我尝试了一个更简单的测试用例,并且它不会以这种方式失败(!)
I tried a simpler test case, and it does not fail in this way (!)
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
这不会失败
我了解这是不尝试此类操作的众多原因之一,但我想了解一下
I understand that this is one of many reasons not to try this sort of thing, but I would like to understand what is going on, nonetheless.
推荐答案
在Python出口清理模块全局变量,并且您的类引用为在运行 __ del __
钩子时已经消失了。
Module globals are cleaned up on Python exit, and your class reference is already gone by the time the __del__
hook is run.
不要指望全局变量在那里。而是使用 type(self)
来获取类引用:
Don't count on globals still being there. Rather, use type(self)
to get the class reference:
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
This is documented in the big Warning section on the object.__del__
hook documentation:
另外,当响应删除模块而调用
__ del __()
时(例如,执行程序时) ,__ del __()
方法引用的其他全局变量可能已经被删除或正在拆除中(例如,进口机械关闭)。因此,__ del __()
方法应该达到维护外部不变性所需的绝对最小值。
Also, when
__del__()
is invoked in response to a module being deleted (e.g., when execution of the program is done), other globals referenced by the__del__()
method may already have been deleted or in the process of being torn down (e.g. the import machinery shutting down). For this reason,__del__()
methods should do the absolute minimum needed to maintain external invariants.
请注意,模块全局变量在词典中维护,因此清除模块全局变量的顺序应受清除时依赖于词典的当前实现和Python版本的顺序约束。
Take into account that module globals are maintained in a dictionary, and thus the order in which they are cleared is subject to the current implementation-and-Python-version-dependent order of the dictionary when being cleared.
这篇关于静态类成员/类引用的生命周期?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!