Проспект (или циклический) импортирует в Python

Я нашел грязный способ сделать то же самое, отфильтровывая по версии выпуска по: ]

Я не знаю, как фильтровать по номеру версии.

Есть идеи?

316
задан NullUserException 6 October 2012 в 08:07
поделиться

5 ответов

Это было действительно хорошее обсуждение этого вопроса на comp.lang.python в прошлом году. Он довольно подробно отвечает на ваш вопрос.

Импорт действительно довольно прост. Просто помните следующее:

'import' и 'from xxx import yyy' являются исполняемыми операторами. Они выполняют когда запущенная программа достигает этой строки.

Если модуль отсутствует в sys.modules, то при импорте создается новый модуль. запись в sys.modules, а затем выполняет код в модуле. Это не вернуть управление вызывающему модулю до завершения выполнения.

Если модуль существует в sys.modules, то импорт просто возвращает это модуль, завершил ли он выполнение или нет. Вот почему циклический импорт может возвращать модули, которые кажутся частично пустыми.

Наконец, исполняемый скрипт запускается в модуле с именем __main__, импортируя скрипт под своим именем создаст новый модуль, не связанный с __main __.

Возьмите эту партию вместе, и вы не должны получать никаких сюрпризов при импорте модули.

259
ответ дан Martijn Pieters 23 November 2019 в 01:04
поделиться

Если вы выполните import foo внутри bar и import bar внутри foo , все будет работать нормально. К тому времени, когда что-нибудь действительно запустится, оба модуля будут полностью загружены и будут иметь ссылки друг на друга.

Проблема в том, что вместо этого вы делаете из foo import abc и из bar import xyz . Потому что теперь каждый модуль требует, чтобы другой модуль уже был импортирован (чтобы импортируемое имя существовало), прежде чем его можно будет импортировать.

это будет работать нормально. К тому времени, когда что-нибудь действительно запустится, оба модуля будут полностью загружены и будут иметь ссылки друг на друга.

Проблема в том, что вместо этого вы делаете из foo import abc и из bar import xyz . Потому что теперь каждый модуль требует, чтобы другой модуль уже был импортирован (чтобы импортируемое имя существовало), прежде чем его можно будет импортировать.

это будет работать нормально. К тому времени, когда что-нибудь действительно запустится, оба модуля будут полностью загружены и будут иметь ссылки друг на друга.

Проблема в том, что вместо этого вы делаете из foo import abc и из bar import xyz . Потому что теперь каждый модуль требует, чтобы другой модуль уже был импортирован (чтобы импортируемое имя существовало), прежде чем его можно будет импортировать.

268
ответ дан user2357112 supports Monica 23 November 2019 в 01:04
поделиться

Циклический импорт завершается, но нужно соблюдать осторожность, чтобы не использовать циклически импортированные модули во время инициализации модуля.

Рассмотрим следующие файлы:

a.py :

print "a in"
import sys
print "b imported: %s" % ("b" in sys.modules, )
import b
print "a out"

b.py:

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 в ), интерпретатор Python больше не импортирует b , поскольку он уже существует в модуле dict.

Если вы попытаетесь получить доступ к bx из a во время инициализации модуля , вы получите AttributeError .

Добавьте следующую строку в a.py :

print b.x

Затем выведите:

97
ответ дан the Tin Man 23 November 2019 в 01:04
поделиться

У меня есть пример, который меня поразил!

foo.py

import bar

class gX(object):
    g = 10

bar.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
8
ответ дан Mohith 23 November 2019 в 01:04
поделиться

Существует много больших ответов здесь. В то время как существуют обычно быстрые решения проблемы, некоторые из которых чувствуют больше pythonic, чем другие, если у Вас есть роскошь выполнения некоторого рефакторинга, другой подход должен проанализировать организацию Вашего кода и попытаться удалить круговую зависимость. Можно найти, например, что Вы имеете:

файл a.py

from b import B

class A:
    @staticmethod
    def save_result(result):
        print('save the result')

    @staticmethod
    def do_something_a_ish(param):
        A.save_result(A.use_param_like_a_would(param))

    @staticmethod
    def do_something_related_to_b(param):
        B.do_something_b_ish(param)

B.py

from a import A

class B:
    @staticmethod
    def do_something_b_ish(param):
        A.save_result(B.use_param_like_b_would(param))

Файла В этом случае, просто переместив один статический метод для отдельного файла, говорят c.py:

файл c.py

def save_result(result):
    print('save the result')

позволит удалять save_result метод от A и таким образом позволит удалять импорт от в b:

Пересмотренный файл a.py

from b import B
from c import save_result

class A:
    @staticmethod
    def do_something_a_ish(param):
        A.save_result(A.use_param_like_a_would(param))

    @staticmethod
    def do_something_related_to_b(param):
        B.do_something_b_ish(param)

Пересмотренный файл b.py

from c import save_result

class B:
    @staticmethod
    def do_something_b_ish(param):
        save_result(B.use_param_like_b_would(param))

, Таким образом, если у Вас есть инструмент (например, pylint или PyCharm), который сообщает относительно методов, которые могут быть статическими, просто бросив staticmethod, декоратор на них не мог бы быть лучшим способом заставить предупреждение замолчать. Даже при том, что метод кажется связанным с классом, могло бы быть лучше выделить его, особенно если у Вас есть несколько тесно связанных модулей, которым, возможно, понадобилась бы та же функциональность, и Вы намереваетесь практиковать принципы DRY.

0
ответ дан 23 November 2019 в 01:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: