【问题标题】:Why is the value of __name__ changing after assignment to sys.modules[__name__]?为什么分配给 sys.modules[__name__] 后 __name__ 的值会发生变化?
【发布时间】:2011-07-18 22:39:34
【问题描述】:

在尝试执行类似于 Alex Martelli 的名为 Constants in Python 的 ActiveState 配方中的内容时,我遇到了意外的副作用(在 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__': 条件在分配后按预期工作(但不再如此)。

FWIW,我还注意到名称 _test 在分配后也从类对象反弹到 None。我觉得奇怪的是他们正在反弹到None,而不是完全消失......

更新:

我想补充一点,鉴于所发生的情况,任何实现if __name__ == '__main__': 效果的变通方法将不胜感激。蒂亚!

【问题讨论】:

    标签: python module


    【解决方案1】:

    发生这种情况是因为您在执行 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'>
    

    希望这能说明问题。

    【讨论】:

    • 并且“用无覆盖所有内容”行为来自模块析构函数故意清除模块中定义的函数和模块__dict__之间的引用循环。
    • 不错的答案和出色的解决方法。我从来没有考虑过删除对模块的sys.modules[] 引用可能会导致它立即被破坏,因为它的引用计数变为零(特别是考虑到它是由模块本身的代码完成的)。谢谢!
    • 根据您的解决方法建议,我已将 sys.modules[__name__] = _test() 替换为 _ref, sys.modules[__name__] = sys.modules[__name__], _test(),一切似乎又好了。
    • @martineau:很高兴有帮助:)
    • ref = sys.modules['__main__'] 在导入 test.py 时被破坏。应该是ref = sys.modules[__name__]
    【解决方案2】:

    如果我将任何内容分配给sys.modules['__main__'],我会得到一个严重损坏的环境。不是这种确切的行为,而是我所有的全局变量和内置函数都消失了。

    sys.modules 没有被记录为在写入时会以任何特定方式表现,只是模糊地表明您可以将其用于“重新加载技巧”(甚至在这种用法中也存在一些重大陷阱)。

    我不会为它写一个非模块并且期望除了痛苦之外的任何东西。我认为这个食谱完全被误导了。

    【讨论】:

    • 在python REPL中sys.modules['__main__']指的是内置模块(&lt;module '__main__' (built-in)&gt;),所以如果你覆盖它,内置模块将被删除,所以你将无法访问任何内置函数了。
    • 这不是误导,它是甜蜜的......当然,每次你在 sys 模块中写入 的东西时,你应该知道“Here be dragons”。 ;-)
    猜你喜欢
    • 1970-01-01
    • 2017-05-19
    • 2018-11-22
    相关资源
    最近更新 更多