9 ответов:
была действительно хорошая дискуссия по этому поводу в комп.ленг.питон в прошлом году. Он отвечает на ваш вопрос довольно тщательно.
импорт довольно прост на самом деле. Просто помните следующее:
'и' от ХХХ импорт ыыы являются исполняемых операторов. Они исполняют когда запущенная программа достигает этой строки.Если модуль не в sys.модули, затем импорт создает новый модуль вход в систему системный.модули и затем выполняет код в модуле. Это не возвращайте управление вызывающему модулю до завершения выполнения.
Если модуль существует в sys.модули затем импорт просто возвращает это модуль независимо от того, завершил ли он выполнение. Это причина, почему циклический импорт может возвращать модули, которые кажутся частично пустыми.
наконец, выполняемый скрипт выполняется в модуле с именем _ _ main__, импортируя скрипт под свой собственный имя создаст новый модуль, не связанный с __главный.__
возьмите эту партию вместе, и вы не должны получать никаких сюрпризов при импорте модули.
если у вас
import fooвнутриbarиimport barвнутриfoo, он будет работать нормально. К тому времени, что на самом деле работает, оба модуля будут полностью загружены и будут иметь ссылки друг на друга.проблема в том, когда вместо этого вы делаете
from foo import abcиfrom bar import xyz. Потому что теперь каждый модуль требует, чтобы другой модуль уже был импортирован (чтобы имя, которое мы импортируем, существовало), прежде чем его можно будет импортировать.
циклический импорт завершается, но вы должны быть осторожны, чтобы не использовать циклически импортированные модули во время инициализации модуля.
рассмотрим следующие файлы:
а.пы:
print "a in" import sys print "b imported: %s" % ("b" in sys.modules, ) import b print "a out"б.пы:
print "b in" import a print "b out" x = 3если вы выполняете a.py, вы получите следующее:
$ python a.py a in b imported: False b in a in b imported: True a out b out a outо втором импорте b.py (во втором
a in), интерпретатор Python не импортируетbопять же, потому что он уже существует в модуль дикт.если вы попытаетесь получить доступ к
b.xСaво время инициализации модуля, вы получитеAttributeError.добавьте следующую строку в
a.py:print b.xтогда выход:
$ python a.py a in b imported: False b in a in b imported: True a out Traceback (most recent call last): File "a.py", line 4, in <module> import b File "/home/shlomme/tmp/x/b.py", line 2, in <module> import a File "/home/shlomme/tmp/x/a.py", line 7, in <module> print b.x AttributeError: 'module' object has no attribute 'x'это потому, что модули выполняются при импорте и в то время
b.xдоступна, строкаx = 3еще не выполнено, что произойдет только послеb out.
поскольку другие ответы описывают этот шаблон, он приемлем в python:
def dostuff(self): from foo import bar ...что позволит избежать выполнения инструкции import при импорте файла другими модулями. Только если существует логическая циклическая зависимость, это не удастся.
большинство круговых импорта на самом деле не являются логическим круговым импортом, а скорее повышают
ImportErrorошибки, так какimport()оценивает операторы верхнего уровня всего файла, когда называемый.эти
ImportErrorsпочти всегда можно избежать, если вы положительно хотите, чтобы ваш импорта на вершине:рассмотрим этот круговой импорт:
Приложение
# profiles/serializers.py from images.serializers import SimplifiedImageSerializer class SimplifiedProfileSerializer(serializers.Serializer): name = serializers.CharField() class ProfileSerializer(SimplifiedProfileSerializer): recent_images = SimplifiedImageSerializer(many=True)Приложение Б
# images/serializers.py from profiles.serializers import SimplifiedProfileSerializer class SimplifiedImageSerializer(serializers.Serializer): title = serializers.CharField() class ImageSerializer(SimplifiedImageSerializer): profile = SimplifiedProfileSerializer()от Дэвида Бизли отличный разговор модули и пакеты: Живи и дай умереть! - PyCon 2015,
1:54:00, вот способ борьбы с циклическим импортом в python:try: from images.serializers import SimplifiedImageSerializer except ImportError: import sys SimplifiedImageSerializer = sys.modules[__package__ + '.SimplifiedImageSerializer']это пытается импортировать
SimplifiedImageSerializerи еслиImportErrorподнимается, потому что он уже импортирован, он будет тянуть его из importcache.PS: вы должны прочитать весь этот пост в голосе Дэвида Бизли.
у меня есть пример, который поразил меня!
foo.py
import bar class gX(object): g = 10bar.py
from foo import gX o = gX()main.py
import foo import bar print "all done"в командной строке: $ python main.py
Traceback (most recent call last): File "m.py", line 1, in <module> import foo File "/home/xolve/foo.py", line 1, in <module> import bar File "/home/xolve/bar.py", line 1, in <module> from foo import gX ImportError: cannot import name gX
Я полностью согласен с ответом pythoneer здесь. Но я наткнулся на некоторый код, который был испорчен циклическим импортом и вызвал проблемы при попытке добавить модульные тесты. Поэтому, чтобы быстро исправить его, не меняя все, что вы можете решить проблему, выполнив динамический импорт.
# Hack to import something without circular import issue def load_module(name): """Load module using imp.find_module""" names = name.split(".") path = None for name in names: f, path, info = imp.find_module(name, path) path = [path] return imp.load_module(name, f, path[0], info) constants = load_module("app.constants")опять же, это не постоянное исправление, но может помочь кому-то, кто хочет исправить ошибку импорта, не меняя слишком много кода.
Ура!
модуль a.py :
import b print("This is from module a")модуль b.py
import a print("This is from module b")запуск "модуля a" выведет:
>>> 'This is from module a' 'This is from module b' 'This is from module a' >>>он выводил эти 3 строки, в то время как он должен был выводить infinitival из-за кругового импорта. Что происходит строка за строкой при запуске "модуля a", указано здесь:
- первая строка
import b. так что он посетит модуль b- первая строка в модуле b -
import a. так что посетите модуль- первая строка в модуле a -
import bно обратите внимание, что эта строка больше не будет выполняться, поскольку каждый файл в python выполняет строку импорта только один раз, не имеет значения, где и когда он выполняется. так он перейдет к следующей строке и печати"This is from module a".- после завершения посещения всего модуля a из модуля b мы все еще находимся в модуле b. поэтому следующая строка будет печатать
"This is from module b"- модуль линия B полностью выполнены. поэтому мы вернемся к модулю a, где мы начали модуль b.
- строка импорта b уже выполнена и не будет выполнена снова. следующая строка будет печатать
"This is from module a"и программа будет закончена.
круговой импорт может быть запутанным, потому что импорт делает две вещи:
- он выполняет импортированный модуль код
- добавляет импортированный модуль в таблицу глобальных символов модуля импорта
первый делается только один раз, в то время как последний в каждом операторе импорта. Циклический импорт создает ситуацию, когда при импорте модуля используется импортированный модуль с частично выполненным кодом. В следствии он не будет видеть объекты, созданные после импорта. Ниже код пример демонстрирует это.
круговой импорт не является окончательным злом, которого следует избегать любой ценой. В некоторых фреймворках, таких как Flask, они вполне естественны, и настройка вашего кода для их устранения не делает код лучше.
main.py
print 'import b' import b print 'a in globals() {}'.format('a' in globals()) print 'import a' import a print 'a in globals() {}'.format('a' in globals()) if __name__ == '__main__': print 'imports done' print 'b has y {}, a is b.a {}'.format(hasattr(b, 'y'), a is b.a)b.by
print "b in, __name__ = {}".format(__name__) x = 3 print 'b imports a' import a y = 5 print "b out"а.ру
print 'a in, __name__ = {}'.format(__name__) print 'a imports b' import b print 'b has x {}'.format(hasattr(b, 'x')) print 'b has y {}'.format(hasattr(b, 'y')) print "a out"python main.py вывод с комментариями
import b b in, __name__ = b # b code execution started b imports a a in, __name__ = a # a code execution started a imports b # b code execution is already in progress b has x True b has y False # b defines y after a import, a out b out a in globals() False # import only adds a to main global symbol table import a a in globals() True imports done b has y True, a is b.a True # all b objects are available
хорошо, я думаю, что у меня есть довольно крутое решение. Допустим, у вас есть файл
aи файлb. У вас естьdefилиclassв файлеbчто вы хотите использовать в модулеa, но у вас есть что-то еще, либо adef,class, или переменная из файлаaчто вам нужно в вашем определении или классе в файлеb. Что вы можете сделать, это, в нижней части файлаa, после вызова функции или класса в файлеaэто необходимо в файлеb, но прежде чем вызов функции или класса из файлаbчто нужно для файлаa, сказалimport bТогда, и вот это основная часть, во всех определениях или классы в файлеbчто нужноdefилиclassиз файлаa(назовем егоCLASS), ты говоришьfrom a import CLASSэто работает, потому что вы можете импортировать файл
bбез Python выполнения любого из операторов импорта в файлеb, и таким образом вы избегаете любого круга импортозамещающий.например:
файл a:
class A(object): def __init__(self, name): self.name = name CLASS = A("me") import b go = B(6) go.dostuffфайл b:
class B(object): def __init__(self, number): self.number = number def dostuff(self): from a import CLASS print "Hello " + CLASS.name + ", " + str(number) + " is an interesting number."вуаля.
Comments