Нечетное поведение с импортом в текущем каталоге [дубликат]

Вы должны запускать приложение App Engine как гибкое приложение для среды, которое построено поверх экземпляров Compute Engine. Стандартная среда App Engine и облачные функции находятся в разных сетях, чем Compute Engine, и не могут использовать VPN или VPC для соединения между ними.

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

9 ответов

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

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

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

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

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

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

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

231
ответ дан Martijn Pieters 3 September 2018 в 13:43
поделиться

Хорошо, я думаю, что у меня довольно крутое решение. Допустим, у вас есть файл a и файл b. У вас есть def или class в файле b, который вы хотите использовать в модуле a, но у вас есть что-то еще, либо def, 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."

Voila.

-2
ответ дан das-g 3 September 2018 в 13:43
поделиться

Циркулярный импорт может сбивать с толку, потому что импорт делает две вещи:

  1. он выполняет импортированный код модуля
  2. добавляет импортируемый модуль для импорта глобальной таблицы символов модуля

Первый выполняется только один раз, а последний - в каждом заявлении импорта. Циркулярный импорт создает ситуацию, когда импортирующий модуль использует импортированный с частично выполненным кодом. В результате он не увидит объекты, созданные после оператора импорта. Ниже образец кода демонстрирует это.

Циркулярный импорт не является наивысшим злом, которого можно избежать любой ценой. В некоторых рамках, таких как 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"

a.py

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
0
ответ дан Jacek Błocki 3 September 2018 в 13:43
поделиться

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

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 3 September 2018 в 13:43
поделиться

Модуль 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 строки, пока он должен выводить бесконечность из-за циклического импорта. Что происходит строка за строкой при запуске «Module a»:

  1. Первая строка - import b. поэтому он посетит модуль b
  2. . Первая строка в модуле b - import a. поэтому он будет посещать модуль a
  3. . Первая строка в модуле a - import b, но отмечает, что эта строка больше не будет выполняться больше , поскольку каждый файл на python выполняет импортировать строку только один раз, не имеет значения, где и когда он выполняется. поэтому он перейдет к следующей строке и напечатает "This is from module a".
  4. После завершения посещения всего модуля a из модуля b мы все еще находимся в модуле b. поэтому следующая строка будет печатать "This is from module b"
  5. . Строки модуля b выполняются полностью. поэтому мы вернемся к модулю a, где мы запустили модуль b.
  6. строка импорта b была уже выполнена и больше не будет выполнена. следующая строка будет печатать "This is from module a", и программа будет закончена.
0
ответ дан Mohsen Haddadi 3 September 2018 в 13:43
поделиться

Я полностью согласен с ответом 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")

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

Приветствия!

3
ответ дан radtek 3 September 2018 в 13:43
поделиться

Как и другие ответы, этот шаблон допустим в python:

def dostuff(self):
     from foo import bar
     ...

. Это позволит избежать выполнения оператора импорта, когда файл импортируется другими модулями. Только если существует логическая циклическая зависимость, это не сработает.

Большинство Circular Imports на самом деле не являются логическим циклическим импортом, а скорее повышают ошибки ImportError из-за того, как import() оценивает операторы верхнего уровня весь файл при вызове.

Эти ImportErrors можно почти всегда избегать, если вы действительно хотите, чтобы ваш импорт был сверху:

Рассмотрим этот циклический импорт:

App A

# profiles/serializers.py

from images.serializers import SimplifiedImageSerializer

class SimplifiedProfileSerializer(serializers.Serializer):
    name = serializers.CharField()

class ProfileSerializer(SimplifiedProfileSerializer):
    recent_images = SimplifiedImageSerializer(many=True)

Приложение B

# images/serializers.py

from profiles.serializers import SimplifiedProfileSerializer

class SimplifiedImageSerializer(serializers.Serializer):
    title = serializers.CharField()

class ImageSerializer(SimplifiedImageSerializer):
    profile = SimplifiedProfileSerializer()

От David Beazleys отличный разговор Модули и пакеты: Live и Let Die! - 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: Вы должны прочитать весь этот пост в голосе Дэвида Бэйсли.

22
ответ дан Sebastian Wozny 3 September 2018 в 13:43
поделиться

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

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

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

Если вы попытаетесь получить доступ к 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.

91
ответ дан the Tin Man 3 September 2018 в 13:43
поделиться

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

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

215
ответ дан user2357112 3 September 2018 в 13:43
поделиться
Другие вопросы по тегам:

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