Почему значение __name__ меняется после присвоения sys.modules [__ name__]?
При попытке сделать что-то похожее на то, что в рецепте ActiveState под названием Constants in 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__':
работало так, как ожидалось после назначения (но больше не работает).
FWIW, я также заметил, что после None
имя _test
получает от объекта класса до None
. Мне кажется странным, что они отскакивают до None
, а не исчезают вообще...
Update:
Я хотел бы добавить, что любые обходные пути для достижения эффекта if __name__ == '__main__':
, учитывая то, что происходит, будут с большой благодарностью. ТИА!
Ответы
Ответ 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 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.
EDIT:
Исправление будет выполняться следующим образом:
class _test(object): pass
import sys
ref = sys.modules[__name__] # Create another reference of this module.
sys.modules[__name__] = _test() # Now when it overwritten it will not be
# deleted because a reference to it still
# exists.
print __name__, _test
# __main__ <class '__main__._test'>
Надеюсь, это объяснит все.
Ответ 2
Если я что-то присваиваю sys.modules['__main__']
, я получаю строго разбитую среду. Не точное поведение, но все мои глобальные и встроенные функции исчезают.
sys.modules
не документируется, чтобы вести себя каким-либо особым образом при написании, но смутно, что вы можете использовать его для "перезагрузки трюков" (и есть некоторые значительные ловушки даже для этого использования).
Я бы не писал для него немодуль и не ожидал ничего, кроме боли. Я думаю, что этот рецепт полностью ошибочен.