2011-03-19 134 views
15

虽然试图做类似什么是由亚历克斯·马尔泰利题为Constants in Python的ActiveState的配方什么的,我遇到了意想不到的副作用(在Python 2.7),在sys.modules指定一个类实例的条目 - 即这样做显然改变,如下面的代码片段所示的__name__None值(它打破了代码的一部分在配方):为什么赋值给sys.modules [__ name__]后__name__的值发生了变化?

class _test(object): pass 

import sys 
print '# __name__: %r' % __name__ 
# __name__: '__main__' 
sys.modules[__name__] = _test() 
print '# __name__: %r' % __name__ 
# __name__: None 

if __name__ == '__main__': # never executes... 
    import test 
    print "done" 

我想明白为什么会这样。我不相信这是Python 2.6和更早版本的方式,因为我有一些旧代码,显然if __name__ == '__main__':条件在分配之后按预期工作(但不再是)。

FWIW,我也注意到名字_test在分配后也从类对象反弹到None。这似乎很奇怪,我认为他们是反弹None,而不是完全消失......

更新:

我想补充一点,对于实现if __name__ == '__main__':效果的任何变通办法,给什么发生将不胜感激。 TIA!

回答

25

发生这种情况的原因是,您在执行sys.modules[__name__] = _test()时已覆盖模块,因此您的模块已被删除(因为模块不再有任何引用,并且引用计数器为零,因此它被删除),但同时解释仍然有字节代码,以便它仍然可以工作,但是你的模块中返回None每一个变量(这是因为Python将所有模块中的变量None当它删除)。

class _test(object): pass 

import sys 
print sys.modules['__main__'] 
# <module '__main__' from 'test.py'> <<< the test.py is the name of this module 
sys.modules[__name__] = _test() 
# Which is the same as doing sys.modules['__main__'] = _test() but wait a 
# minute isn't sys.modules['__main__'] was referencing to this module so 
# Oops i just overwrite this module entry so this module will be deleted 
# it's like if i did: 
# 
# import test 
# __main__ = test 
# del test 
# __main__ = _test() 
# test will be deleted because the only reference for it was __main__ in 
# that point. 

print sys, __name__ 
# None, None 

import sys # i should re import sys again. 
print sys.modules['__main__'] 
# <__main__._test instance at 0x7f031fcb5488> <<< my new module reference. 

编辑:

一个修复程序会做这样的:

class _test(object): pass 

import sys 
ref = sys.modules[__name__] # Create another reference of this module. 
sys.modules[__name__] = _test() # Now when it's overwritten it will not be 
            # deleted because a reference to it still 
            # exists. 

print __name__, _test 
# __main__ <class '__main__._test'> 

希望这能解释的事情。

+3

而“用None覆盖所有内容”行为来自模块析构函数故意清除模块中定义的函数与模块__dict__'之间的引用循环。 – ncoghlan 2011-03-20 00:03:21

+0

很好的答案和优秀的解决方法。我从来没有考虑过删除一个'sys。由于引用计数为零(特别是考虑到模块本身由代码完成),所以对模块的引用可能会导致其立即销毁。谢谢! – martineau 2011-03-20 18:31:49

+0

根据您的解决方法建议,我用'_ref,sys.modules [__ name__] = sys.modules [__ name__],_test()'替换了'sys.modules [__ name__] = _test()',好吧。 – martineau 2011-03-20 19:14:39

1

如果我给你什么sys.modules['__main__']我得到一个严重破损的环境。不是这个确切的行为,但我所有的全局变量和内建变量都消失了。

sys.modules在写入时未被记录为以任何特定方式表现,只是模糊地表示您可以将其用于“重新加载技巧”(甚至有一些重要的陷阱甚至是该用法)。

我不会写非模块,并期待什么,但疼痛。我认为这个配方是完全错误的。

+0

在Python REPL'sys.modules中[“__主__”]'指内置模块('<模块“__main__”(内置)>'),所以如果将其覆盖,内置的模块将被删除,因此您将不再有任何内置功能。 – mouad 2011-03-20 00:44:55

+3

它没有被误导,它很甜蜜......当然,每当你在sys模块中写入*时,你都应该知道“Here is dragons”。 ;-) – 2011-06-13 12:34:45

相关问题