2011-03-19 131 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

相關問題