Почему значение __name__ меняется после присвоения sys.modules [__name__]? - PullRequest
18 голосов
/ 20 марта 2011

Пытаясь сделать что-то похожее на то, что в рецепте ActiveState Алекса Мартелли под названием Константы в Python , я столкнулся с неожиданным побочным эффектом (в 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__':, учитывая то, что происходит, будут с благодарностью. ТИА!

Ответы [ 2 ]

29 голосов
/ 20 марта 2011

Это происходит потому, что вы перезаписали свой модуль, когда сделали 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'>

Надеюсь, это объяснит вещи.

0 голосов
/ 20 марта 2011

Если я назначу что-либо для sys.modules['__main__'], я получаю сильно нарушенную среду. Не такое точное поведение, но все мои глобалы и встроенные объекты исчезают.

sys.modules не задокументировано, что оно ведет себя каким-либо особым образом при записи, только смутно, что вы можете использовать его для «перезагрузки трюков» (и есть некоторые существенные ловушки даже для такого использования).

Я бы не стал писать немодуль и не ожидал ничего, кроме боли. Я думаю, что этот рецепт полностью ошибочен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...