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 ++ довгий час. Я здогадуюсь, що помилка пов'язана з імпортом сутності два рази, один раз в основному, а пізніше у фізиці, але я не знаю вирішення проблеми. Хтось може допомогти?


Яка структура каталогу, де вони зберігаються та в яких каталогах?
Бен

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?
HeyWatchЦе

Відповіді:


502

У вас кругозалежний імпорт. physics.pyімпортується з entityраніше Entвизначеного класу і physicsнамагається імпортувати entityте, що вже ініціалізується. Видаліть залежність до physicsз entityмодуля.


5
Ви можете зробити багато чого, ніж перефактурувати свій код. Якщо ви не посилаєтесь на визначення фізики в конструкторі Ent, перенесіть mport просто під Ent. Якщо це зробити, додайте такий метод, як setPhysics, щоб включити імпорт після конструктора.
Теему Іконен

12
@jsells Оскільки ви довго працювали з C ++, вам слід знати, що два класи НІКОЛИ не повинні залежати один від одного. Це надзвичайно важливо для C ++, і навіть якщо це не річ №1 в Python, все-таки дійсно гарна ідея дотримуватися цього правила. Ніколи не мати двох класів, які знають один одного. Якщо вам потрібна допомога в створенні структури для ваших класів, розмістіть і решту коду. Як саме (з точки зору коду) є Entityі Physicsпов'язані один з одним? Я впевнений, що існує вирішення того, що ви намагаєтеся зробити.

7
@ user2032433 Це дійсно залежить від того, що ви маєте на увазі під «пізнавати один одного». Це правда, що хороший дизайн зазвичай створює дерево однобічної залежності, і це, як правило, найкращий підхід. Але з цього є винятки. Класи C ++, безумовно, можуть посилатися один на одного циркулярно. (Хоча неможливо, щоб вони складалися один з одного.) Без прямого оголошення, це проблема в Python, який не завжди має рішення C ++.
Джон Макфарлейн

93
Заява "два класи НІКОЛИ не залежать один від одного" - це сміття. Двостороння (двонаправлена) навігація дуже поширена в орієнтації на об'єкти. books.google.co.uk/…
Мартін Спамер

5
Шаблон дизайну стану (наприклад) зазвичай реалізується з класом контексту та інтерфейсом стану. Екземпляри стану передаються екземпляру контексту, щоб вони могли викликати setState. Це вимагає від держави знання про контекст і навпаки. Як ця класична конструкція "погана в коді"? Насправді це саме проблема, з якою я борюсь у Python, але не довелося, коли я реалізував State на Java.
Auspice

141

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

наприклад:

import SomeModule

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

це (принаймні в деяких випадках) обійде помилку.


38
кругові залежності найкраще обійти
ckb

4
База на pep8, введення методу імпорту всередину не є хорошою практикою
TomSawyer

@TomSawyer Чому?
Kröw

@TomSawyer Я не рекомендую цього, але це швидке рішення, яке може позбавити вас від прив'язки
bharling

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

Щоб зрозуміти логіку дуже важливо. Ця проблема з'являється, оскільки посилання стає мертвою петлею.

Якщо ви не хочете змінювати логіку, ви можете перенести деяку заяву про імпорт, яка спричинила 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

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() 

17

Я також отримав цю помилку з іншої причини ...

from my_sub_module import my_function

Основний сценарій мав закінчення рядків Windows. my_sub_moduleмали закінчення рядків UNIX. Зміни їх на однакові виправили проблему. Вони також повинні мати однакове кодування символів.


7

Як вже було сказано, це викликано круговою залежністю . Що вже не згадувалося, що коли ви використовуєте модуль набору Python та імпортуєте клас лише для коментування типів , ви можете використовувати посилання Forward :

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

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

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.py, тому python не знав, що імпортувати. Зміна імені файлів допомагає.
Марек Бодзьоній

5

Тут ще не бачите цього - це неймовірно нерозумно, але переконайтесь, що ви імпортуєте правильну змінну / функцію.

Я отримував цю помилку

ImportError: неможливо імпортувати ім’я IMPLICIT_WAIT

тому що моя змінна була насправді IMPLICIT_TIMEOUT.

коли я змінив імпорт, щоб використовувати правильну назву, більше не отримав помилку 🤦‍♂️


1
Я був готовий вбити когось, намагаючись зрозуміти, чому from PIL import Pillowне працює. 😠
аалаап

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

Також не має безпосереднього відношення до ОП, але, якщо не перезапустити консоль PyCharm Python, після додавання нового об'єкта до модуля, це також чудовий спосіб отримати дуже заплутаний характерImportError: Cannot import name ...

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


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!

2

У моєму випадку я працював у зошиті Jupyter, і це сталося через імпорт, який уже кешувався, коли я визначив клас / функцію у своєму робочому файлі.

Я перезапустив своє ядро ​​Jupyter і помилка зникла.


1

Спеціально для цього запитувача, але ця сама помилка покаже, чи ім'я класу у вашому імпорті не відповідає визначенню у файлі, з якого ви імпортуєте.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.