为什么在赋值给sys.modules [__ name__]后__name__的值会发生变化?

mar*_*eau 18 python module

在尝试做类似于Alex Martelli 的ActiveState配方标题为Python中Constants时,我遇到了意外的副作用(在Python 2.7中),它将类实例分配给sys.moduleshas中的一个条目- 即显然这样做更改__name__to 的值,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"
Run Code Online (Sandbox Code Playgroud)

我想知道为什么会这样.我不相信它在Python 2.6和早期版本中是这样的,因为我有一些较旧的代码,显然if __name__ == '__main__':条件在赋值后按预期工作(但不再有).

FWIW,我也注意到这个名字在分配后也会_test从一个类对象反弹None回来.我觉得很奇怪他们正在反弹None而不是完全消失......

更新:

我想补充一点,任何实现效果的变通办法if __name__ == '__main__':都会受到高度赞赏.TIA!

mou*_*uad 29

发生这种情况是因为你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.
Run Code Online (Sandbox Code Playgroud)

编辑:

修复将是这样做的:

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'>
Run Code Online (Sandbox Code Playgroud)

希望这能解释一切.

  • 并且"用None覆盖所有内容"行为来自模块析构函数故意清除模块中定义的函数和模块`__dict__`之间的引用循环. (5认同)
  • 导入`test.py`时,`ref = sys.modules ['__ main __']`被破坏.它应该是`ref = sys.modules [__ name __]` (2认同)