ImportError: Невозможно импортировать имя X

540

У меня есть четыре разных файла: основной, векторный, объект и физика. Я не буду публиковать весь код, только импорт, потому что я думаю, что здесь ошибка. (Если хотите, могу выложить больше)

Главный:

import time
from entity import Ent
from vector import Vect
#the rest just creates an entity and prints the result of movement

Сущность:

from vector import Vect
from physics import Physics
class Ent:
    #holds vector information and id
def tick(self, dt):
    #this is where physics changes the velocity and position vectors

Вектор:

from math import *
class Vect:
    #holds i, j, k, and does vector math

Физика:

from entity import Ent
class Physics:
    #physics class gets an entity and does physics calculations on it.

Затем я запускаю из main.py и получаю следующую ошибку:

Traceback (most recent call last):
File "main.py", line 2, in <module>
    from entity import Ent
File ".../entity.py", line 5, in <module>
    from physics import Physics
File ".../physics.py", line 2, in <module>
    from entity import Ent
ImportError: cannot import name Ent

Я очень плохо знаком с Python, но долгое время работал с C ++. Я предполагаю, что ошибка происходит из-за импорта сущности дважды, один раз в основную, а затем в физике, но я не знаю обходного пути. Кто-нибудь может помочь?

jsells
источник
Какова структура каталогов, где они хранятся и в каких каталогах?
Бен
1
взгляните на этот ответ для импорта петель в python: stackoverflow.com/questions/7199466/…
Грегор
В общем, это не хорошая практика кодирования делать from <module> import <name>, или from <modlue> import *. Лучше импортировать в пространство имен модуля, чтобы исключить возможность перезаписи ссылок с одинаковыми именами.
Джоэл Корнетт
1
@jsells Вы должны просто вызывать свои классы, Entityи Vectorвместо Entи Vectнет причин сокращать такие имена. И да, используйте import vectorи тогда x = vector.Vector(0,0,0).
7
Привет @Kevin, так как ты знаешь Java лучше, каково твое впечатление от этой статьи 2008 года, где первое предложение автора относится к тому, как циклические зависимости являются «довольно распространенной практикой» в Java?
HeyWatchThis

Ответы:

503

У вас есть круговой зависимый импорт. physics.pyимпортируется entityдо Entопределения класса и physicsпытается импортировать entityуже инициализированный. Удалить зависимость physicsот entityмодуля.

Теему Иконен
источник
5
Вы ничего не можете сделать, кроме как провести рефакторинг своего кода. Если вы не ссылаетесь на физику в определении конструктора Ent, переместите mport под Ent. Если вы это сделаете, добавьте метод вроде setPhysics, чтобы включить импорт после конструктора.
Теему Иконен
12
@jsells Поскольку вы работали с C ++ «долгое время», вы должны знать, что два класса НИКОГДА не должны зависеть друг от друга. Это чрезвычайно важно в C ++, и даже если это не первое место в Python, все же очень хорошая идея - следовать этому правилу. Никогда не имейте двух классов, которые знают друг друга, никогда. Если вам нужна помощь в создании структуры для ваших классов, опубликуйте и остальную часть кода. Как именно (с точки зрения кода) связаны Entityи Physicsсвязаны друг с другом? Я уверен, что есть обходной путь для того, что вы пытаетесь сделать.
7
@ user2032433 Это действительно зависит от того, что вы подразумеваете под «знать друг друга». Это правда, что хороший дизайн обычно создает дерево односторонних зависимостей, и обычно это лучший подход. Но есть исключения из этого. Классы C ++, безусловно, могут ссылаться друг на друга по кругу. (Хотя они не могут быть составлены друг из друга.) Без предварительного объявления это проблема в Python, который не всегда имеет решение C ++.
Джон Макфарлейн
93
Утверждение «два класса НИКОГДА не должны зависеть друг от друга» является мусором. Двухсторонняя (двунаправленная) навигация очень распространена в ориентации объекта. books.google.co.uk/…
Мартин Спамер
5
Шаблон проектирования State (например) обычно реализуется с помощью класса Context и интерфейса State. Экземпляры State передаются экземпляру Context, чтобы они могли вызывать setState. Это требует, чтобы государство знало о контексте и наоборот. Как эта классическая конструкция «плохо работает с кодом»? На самом деле это именно та проблема, с которой я борюсь в Python, но не пришлось, когда я реализовывал State в Java.
Прошение
142

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

например:

import SomeModule

def someFunction(arg):
    from some.dependency import DependentClass

это (по крайней мере, в некоторых случаях) обойдет ошибку.

bharling
источник
38
круговые зависимости лучше всего обходить
ckb
4
Основываясь на pep8, использование метода импорта внутри не является хорошей практикой
TomSawyer
@ TomSawyer Почему?
Кроу
@ TomSawyer Я не рекомендую это, но это быстрое решение, которое может вывести вас из-под
контроля
117

Это круговая зависимость. Это может быть решено без каких-либо структурных изменений в коде. Проблема возникает потому, что vectorвы требуете, entityчтобы сделать доступными для использования немедленно, и наоборот. Причиной этой проблемы является то, что вы запрашиваете доступ к содержимому модуля, прежде чем он будет готов - с помощью from x import y. Это по сути так же, как

import x
y = x.y
del x

Python способен обнаруживать циклические зависимости и предотвращать бесконечный цикл импорта. По сути, все, что происходит, - это то, что для модуля создается пустой заполнитель (т.е. он не имеет содержимого). Как только циклически зависимые модули скомпилированы, он обновляет импортированный модуль. Это работает примерно так.

a = module() # import a

# rest of module

a.update_contents(real_a)

Чтобы Python мог работать с циклическими зависимостями, вы должны использовать import xтолько стиль.

import x
class cls:
    def __init__(self):
        self.y = x.y

Поскольку вы больше не обращаетесь к содержимому модуля на верхнем уровне, python может скомпилировать модуль без фактического доступа к содержимому циклической зависимости. Под верхним уровнем я подразумеваю строки, которые будут выполняться во время компиляции, а не содержимое функций (например, y = x.y). Статические переменные или переменные класса, обращающиеся к содержимому модуля, также вызовут проблемы.

Дюны
источник
24

Прояснить логику очень важно. Эта проблема появляется, потому что ссылка становится мертвой петлей.

Если вы не хотите менять логику, вы можете поместить оператор import, который вызвал ImportError, в другую позицию файла, например в конец.

a.py

from test.b import b2

def a1():
    print('a1')
    b2()

b.py

from test.a import a1

def b1():
    print('b1')
    a1()

def b2():
    print('b2')

if __name__ == '__main__':
    b1()

Вы получите ошибку импорта: ImportError: cannot import name 'a1'

Но если мы изменим позицию из test.b import b2 в A, как показано ниже:

a.py

def a1():
    print('a1')
    b2()

from test.b import b2

И мы можем получить то, что мы хотим:

b1
a1
b2
g10guang
источник
18

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

A.py

from B import b2
def a1():
    print('a1')
    b2()

B.py

def b1():
   from A import a1
   print('b1')
   a1()

def b2():
   print('b2')
if __name__ == '__main__':
   b1() 
a.patidar
источник
17

Я тоже получил эту ошибку, по другой причине ...

from my_sub_module import my_function

Основной скрипт имел окончания строк в Windows. my_sub_moduleимел окончания строки UNIX. Изменение их на одно и то же решило проблему. Они также должны иметь одинаковую кодировку символов.

marengaz
источник
7

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

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

и удалить зависимость ( импорт ), например, вместо

from my_module import Tree

def func(arg: Tree):
    # code

делать:

def func(arg: 'Tree'):
    # code

(обратите внимание на удаленное importутверждение)

Томаш Бартковяк
источник
6

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

Решение: переименуйте ваш рабочий скрипт на Python

Пример:

  1. ты работаешь в medicaltorch.py
  2. в этом сценарии вы имеете: from medicaltorch import datasets as mt_datasetsгде medicaltorchдолжен быть установлен модуль

Это не удастся с ImportError. Просто переименуйте ваш рабочий скрипт на Python в 1.

Павел
источник
Спасибо, это решает проблему, которая у меня была. Я использовал библиотеку colorama и назвал файл colorama.py, поэтому python не знал, что импортировать. Смена имени файла помогает.
Марек Бодзиони
5

Пока не видите этого - это невероятно глупо, но убедитесь, что вы импортируете правильную переменную / функцию.

Я получаю эту ошибку

ImportError: невозможно импортировать имя IMPLICIT_WAIT

потому что моя переменная была на самом деле IMPLICIT_TIMEOUT.

когда я изменил свой импорт, чтобы использовать правильное имя, я больше не получил ошибку 🤦‍♂️

Ник Брэйди
источник
1
Я был готов убить кого-то, пытаясь понять, почему from PIL import Pillowне работает. A
аалап
5

Если вы импортируете file1.pyиз file2.pyи использовать это:

if __name__ == '__main__':
    # etc

Переменные ниже, чем в file1.py не могут быть импортированы в file2.pyпотому , что __name__ не равно __main__ !

Если вы хотите импортировать что-то из file1.pyв file2.py, вам нужно использовать это в file1.py:

if __name__ == 'file1':
    # etc

В случае сомнений сделайте assertзаявление, чтобы определить,__name__=='__main__'

Николя Жерве
источник
4

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

  1. вы получите что-то вроде:

    python ./main.py

    ImportError: невозможно импортировать имя A

  2. тогда вы запускаете:

    python ./modules/a.py

    ImportError: невозможно импортировать имя B

  3. тогда вы запускаете:

    python ./modules/b.py

    ImportError: невозможно импортировать имя C (какой-то несуществующий модуль или какая-то другая ошибка)

Эвальдс Уртанс
источник
3

Также не имеет непосредственного отношения к OP, но не удается перезапустить консоль PyCharm Python после добавления нового объекта в модуль, также является отличным способом запутатьImportError: Cannot import name ...

Заблуждение заключается в том, что PyCharm автоматически завершит импорт в консоли, но импорт завершится неудачно.

djvg
источник
2

Проблема ясна: круговая зависимость между именами entityи physicsмодулями.

Независимо от импорта всего модуля или только класса, имена должны быть загружены.

Посмотрите этот пример:

# a.py
import b
def foo():
  pass
b.bar()
# b.py
import a
def bar():
  pass
a.foo()

Это будет скомпилировано в:

# a.py
# import b
# b.py
# import a # ignored, already importing
def bar():
  pass
a.foo()
# name a.foo is not defined!!!
# import b done!
def foo():
  pass
b.bar()
# done!

С одним небольшим изменением мы можем решить это:

# a.py
def foo():
  pass
import b
b.bar()
# b.py
def bar():
  pass
import a
a.foo()

Это будет скомпилировано в:

# a.py
def foo():
  pass
# import b
# b.py
def bar():
  pass
# import a # ignored, already importing
a.foo()
# import b done!
b.bar()
# done!
DuniC
источник
2

В моем случае я работал в записной книжке Jupyter, и это происходило из-за того, что импорт уже кэшировался, когда я определил класс / функцию внутри моего рабочего файла.

Я перезапустил свое ядро ​​Jupyter, и ошибка исчезла.

Гарри М
источник
1

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

беннетт
источник