2015-01-13 3 views
3

У меня есть два файла в том же каталоге, который содержит содержимое моей программы poker.py, а другой, имеющий тестовые примеры poker_test.py.Как python оценивает выполнение модуля?

В poker_test.py я выполнить следующие команды для запуска тестовых случаев:

import unittest 
import poker 


class PokerTest(unittest.TestCase): 
     (...) 

Затем в конце poker.py в то время как я разрабатываю у меня есть следующий commnands:

if __name__ == "__main__": 
    #imports Test case and unittest 
    from poker_test import * 
    unittest.main() 

все работает просто отлично (на данный момент), и эта настройка отлично подходит для итеративного развития. Мой вопрос в том, как python оценивает poker.py, когда я его запускаю, учитывая, что poker_test.py зависит от poker.py и наоборот?

У меня есть приблизительная идея, но мне было интересно, что такое «официальный» ответ.

Спасибо, -ГО

+0

Обратите внимание, что UnitTest также поддерживает ограниченные аргументы командной строки: https://docs.python.org/2/library/unittest.html#command- line-interface - В этом случае, а не 'python poker.py' для запуска теста, вы будете делать' python -m unittest poker_test.py', а Боб - ваш дядя. вы можете даже запустить только определенные тесты. 'python -m unittest poker_test.PokerTest.testSomething' – mgilson

ответ

3

С точки зрения того, следует ли вам это делать, как говорит Алекс, избегайте его любой ценой. Циклический импорт - это состояние греха.

С, что в стороне, это интересно посмотреть на то, что происходит (примерно -. Это выглядит как механизм импорта модуль an area that gets tweaked from version to version in Python Мой главный источник для этого был Python 3.4.2 документы по системе импортирования)

Когда линия в poker_test.py:

import poker 

запускается на выполнение, то система сначала проверяет, если модуль уже загружен. Загруженные модули живут в словаре под названием sys.modules.

  • Если модуль импортируется в sys.modules уже, любая ссылка на poker в poker_test.py просто указывает на это пространство имен.(Обратите внимание, что в случае циклического импорта модуль может быть уже добавлен к sys.modules, но заполнение пространства имен может быть не полностью завершено. Выполнение этого модуля может быть приостановлено на данный момент в строке, которая говорит import this_or_that_other_module)
  • Если модуля там нет, система создает новое пространство имен, добавляет его в sys.modules, ищет код, связанный с модулем poker (в данном случае он живет в poker.py) и начинает его выполнять, вводя все переменные во вновь создаваемом пространстве имен.

Так что вы думаете poker.py получает запустить один раз, и poker_test.py получает запустить один раз и уже замечает, что poker провокационный модуль, таким образом, импортирование заканчивается. За исключением ...

Когда модуль запускается как исходный скрипт, он регистрируется как __main__ в sys.modules вместо его фактического имени.

Так poker.py будет называться __main__ модуль, и в результате, когда poker_test пытается бегущие import poker, он не может найти poker под sys.modules. pokerбудет загружаться в, как только __main__ и снова как poker. Циклический импорт неодобрен, но циклический импорт модуля __main__ прямо осужден из-за этой проблемы создания двух идентичных (иш) пространств имен и возможных потенциальных ошибок, которые могут возникнуть.

В коде есть еще две проблемы.

1) from poker_test import *

Потому что вы делаете в import *, вместо того, чтобы все переменные, созданные из poker_test в своем собственном пространстве имен, оно брошено в __main__ имен.

2) if __name__=='__main__':

Потому что вы только импорт из poker_test, если модуль является основной скрипт выполняется, интерпретатор Python не будет трогать эту строку, когда poker импортируется из poker_test. Таким образом, ваш код концептуально не зацикливается. poker как __main__ импорт poker_test который импортирует poker и останавливается там. Просто!

... так что давайте не будем делать круговой импорт.

Некоторые справочные материалы:

Official Python 3.4.2 docs on the import system

2008 comp.lang.python discussion on cyclical imports

1

Это всегда здравое, чтобы избежать циклических зависимостей, как тот, который вы создали здесь. Однако вам повезло, потому что from poker_test import * приходит в самом конце poker.py, т. Е. После того, как последний определил все, что он определяет, поэтому он может быть импортирован в хорошем состоянии циклически зависимым poker_test.py.

Однако, хотя это происходит для текущей версии Python, это не гарантируется спецификацией языка. Для солидности, разорвать круговую зависимость, например, следующим образом:

  • переместить все «существенные» содержимое poker.py до if __name__ чека, например _poker.py
  • в poker.py, просто сделать from _poker import *
  • в poker_test.py, вместо из import poker, используйте import _poker as poker

Таким образом, ваш граф зависимостей становится ациклический, и, как следствие ваш код будет работать так, как предполагалось, в любой правильной версии Python, включая гипотетические будущие :-).

Смежные вопросы