2

我发现了一些非常奇怪的东西。请参阅下面的短代码。

import os

class Logger(object):
    def __init__(self):
        self.pid = os.getpid()
        print "os: %s." %os

    def __del__(self):
        print "os: %s." %os

def temp_test_path():
    return "./[%d].log" %(os.getpid())

logger = Logger()

这旨在用于说明目的。os它只是在类的构造和销毁上打印导入的模块(别管名称Logger)。但是,当我运行它时,模块os似乎“消失”到None了类析构函数中。以下是输出。

os: <module 'os' from 'C:\Python27\lib\os.pyc'>.
os: None.

哪里说os: None.是我的问题。它应该与第一条输出线相同。但是,回头看看上面的 python 代码,在函数temp_test_path(). 如果我稍微改变这个函数的名称,比如说temp_test_pat(),并保持所有其余代码完全相同,然后运行它,我会得到预期的输出(如下)。

os: <module 'os' from 'C:\Python27\lib\os.pyc'>.
os: <module 'os' from 'C:\Python27\lib\os.pyc'>.

除了这是一个错误,我找不到任何解释。你能?顺便说一句,我使用的是 Windows 7 64 位。

4

4 回答 4

4

如果您依靠解释器关闭来调用您__del__,那么很可能是在您被调用os之前该模块已被删除。__del__尝试在你的代码中明确地做 adel logger并睡一会儿。这应该清楚地表明代码按您期望的那样运行。

我还想将您链接到官方文档中的此注释,该注释__del__不保证在 CPython 实现中被调用。

于 2013-02-20T16:01:08.033 回答
4

我已经复制了这个。肯定是有趣的行为。您需要意识到的一件事是,__del__即使在解释器退出时也不能保证调用它——而且在解释器退出时也没有指定的最终确定对象的顺序。

由于您要退出解释器,因此不能保证os没有首先删除。在这种情况下,似乎os实际上是在您的Logger对象之前完成的。这些事情可能会根据globals字典中的顺序发生。

如果我们只是在退出之前打印全局字典的键:

for k in globals().keys():
    print k

你会看到的:

temp_test_path
__builtins__
__file__
__package__
__name__
Logger
os
__doc__
logger

或者:

logger
__builtins__
__file__
__package__
temp_test_pat
__name__
Logger
os
__doc__

注意你的位置logger,特别是与os列表中的位置相比。With temp_test_pat,logger实际上是 finalized First,所以os仍然绑定了一些有意义的东西。但是,您使用temp_test_path.

如果您打算让一个对象在解释器退出之前一直存在,并且您有一些要运行的清理代码,您总是可以使用atexit.register.

于 2013-02-20T16:05:35.347 回答
3

其他人已经给你答案了,关闭期间从模块的命名空间中删除全局变量(例如osLogger和)的顺序未定义。logger

但是,如果您想要解决方法,只需导入os终结器的本地命名空间:

def __del__(self):
    import os
    print "os: %s." %os

此时os模块仍然存在,只是你失去了对它的全局引用。

于 2013-02-20T16:13:35.503 回答
2

这是可以预料的。来自Python 语言参考

此外,当del () 被调用以响应模块被删除时(例如,当程序执行完成时),由del () 方法引用的其他全局变量可能已经被删除或正在被拆除(例如进口机器关闭)。

在大红色警告框中:-)

于 2013-02-20T16:01:23.647 回答