为什么在赋值给sys.modules[__name__]后__name__的值会改变?
在尝试做一些类似于ActiveState的食谱中提到的内容时,标题为Python中的常量,作者是Alex Martelli,我遇到了一个意想不到的副作用(在Python 2.7中)。这个副作用是,当我把一个类的实例赋值给sys.modules
中的某个条目时,__name__
的值似乎变成了None
。下面的代码片段展示了这个问题,这导致食谱中的部分代码无法正常工作:
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__':
的条件判断是正常工作的(但现在不再如此)。
顺便提一下,我还注意到,名称_test
在赋值后也从一个类对象变成了None
。我觉得它们被重新绑定到None
而不是完全消失,这有点奇怪……
更新:
我想补充一下,任何关于如何实现if __name__ == '__main__':
效果的解决方法,考虑到发生的事情,我将非常感激。谢谢!
2 个回答
如果我给 sys.modules['__main__']
赋值什么东西,我的环境就会变得非常糟糕。虽然不是这种具体的情况,但我的全局变量和内置函数都会消失。
sys.modules
的使用并没有详细的文档说明,写入它时并没有特别的行为,只是模糊地提到可以用它来做“重新加载的技巧”(不过即使这样使用也有一些很大的陷阱)。
我不会随便往里面写非模块的东西,也不指望会有什么好结果。我觉得这个做法完全是错误的。
这个问题发生的原因是,你在执行 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'>
希望这样能让你更明白。