Почему Python более строг в отношении циклического импорта при использовании from-import? - PullRequest
1 голос
/ 29 сентября 2011

Я знаю, что Python препятствует любой ситуации, которая может привести вас к циклическому импорту.Но я хотел понять внутреннюю часть Python о том, почему from-imports кажутся произвольно менее прощающими, чем обычный импорт в ситуациях кругового импорта.

Например, этот код компилируется:

# main.py
import CommonUtil

# commonutil.py
import util
class CommonUtil:
    # some code that uses util.Util
    pass

# util.py
import commonutil
class Util:
    # some code that uses commonutil.CommonUtil
    pass

Но этот кодне:

# main.py
import CommonUtil

# commonutil.py
import util
class CommonUtil:
    # some code that uses util.Util
    pass

# util.py
from commonutil import CommonUtil
class Util:
    # some code that uses CommonUtil
    pass

Traceback (most recent call last):
  File "main.py", line 1, in <module>
    import CommonUtil
  File "commonutil.py", line 1, in <module>
    import util
  File "util.py", line 1, in <module>
    from commonutil import CommonUtil
ImportError: cannot import name CommonUtil

Вы не столкнетесь с ошибками компилятора, если не попытаетесь использовать соответствующие классы до завершения всех операций импорта.Но когда вы пытаетесь сделать псевдоним, это не получается.Может кто-нибудь объяснить, что происходит внутри Python, что приводит к тому, что эта ошибка поднимает голову только при использовании from-import?И во-вторых, есть ли простой способ обойти это?(Помимо очевидного «извлечения общего кода из третьего модуля», который я, скорее всего, сделаю в любом случае.)

Ответы [ 2 ]

2 голосов
/ 29 сентября 2011

Модули выполнены сверху вниз.Когда импорт просматривается впервые, выполнение текущего модуля приостанавливается, так что другой модуль может быть импортирован.Когда другой модуль пытается импортировать первый модуль, он получает ссылку на частично выполненный в данный момент модуль.Поскольку код, расположенный после импорта другого модуля, еще не был выполнен, все содержащиеся в нем имена не могут существовать.

main.py

import a

a.py

var1 = 'foo'
import b
var2 = 'bar'

b.py

import a
print a.var1 # works
print a.var2 # fails

Обходной путь - не обращаться к именам в импортированном модуле, пока не завершится его выполнение.

1 голос
/ 29 сентября 2011

см. http://effbot.org/zone/import-confusion.htm#circular-imports для объяснения того, что происходит.

Я предполагаю, что вы запускаете файл main.py.Python сначала попытается загрузить commonutil.Он создаст объект модуля и начнет заполнять его классом, функцией и глобальной переменной при обнаружении их определения.Первый оператор - импорт, поэтому теперь python создает модуль util и начинает его заполнять.Общий модуль существует, но он пуст.В первой версии вы не получаете доступ к общему объекту во время загрузки, так что все в порядке.Во втором вы пытаетесь получить определенную переменную в commonutil, которая не существует в данный момент.Если бы вы использовали что-то вроде f(commonutil.CommonUtil) в первой версии, это бы также привело к сбою.

...