ImportError: impossible d'importer le nom X

540

J'ai quatre fichiers différents nommés: principal, vecteur, entité et physique. Je ne publierai pas tout le code, juste les importations, car je pense que c'est là que se trouve l'erreur. (Si vous voulez, je peux poster plus)

Principale:

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

Entité:

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

Vecteur:

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

La physique:

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

Je lance ensuite depuis main.py et j'obtiens l'erreur suivante:

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

Je suis très nouveau sur Python, mais je travaille avec C ++ depuis longtemps. Je suppose que l'erreur est due à l'importation de l'entité deux fois, une fois en principal et plus tard en physique, mais je ne connais pas de solution. Quelqu'un peut-il aider?

jsells
la source
Quelle est la structure de répertoires où ils sont stockés et dans quels répertoires?
Ben
1
jetez un oeil à cette réponse pour l'importation de boucles en python: stackoverflow.com/questions/7199466/…
Gregor
En général, ce n'est pas une bonne pratique de codage à faire from <module> import <name>, ou from <modlue> import *. Mieux vaut importer sous l'espace de noms du module pour éviter le risque d'écraser des références de nom identique.
Joel Cornett
1
@jsells Vous devez simplement appeler vos classes Entityet Vectorau lieu de Entet Vect, il n'y a aucune raison de raccourcir ces noms. Et oui, utilisez import vectoret ensuite x = vector.Vector(0,0,0).
7
Hé @Kevin puisque vous connaissez mieux Java, quelle est votre impression de cet article de 2008 où la première phrase de l'auteur fait référence à la façon dont les dépendances circulaires sont "une pratique assez courante" en Java?
HeyWatchThis

Réponses:

503

Vous avez des importations dépendantes circulaires. physics.pyest importé entityavant que la classe ne Entsoit définie et physicsessaie d'importer entityqui est déjà en cours d'initialisation. Supprimez la dépendance physicsdu entitymodule.

Teemu Ikonen
la source
5
Il n'y a pas grand-chose que vous puissiez faire que de refactoriser votre code. Si vous ne faites pas référence à la physique dans la définition du constructeur Ent, déplacez mport juste sous l'entité. Si vous le faites, ajoutez une méthode comme setPhysics pour activer l'importation après le constructeur.
Teemu Ikonen
12
@jsells Puisque vous avez travaillé avec C ++ "pendant longtemps", vous devez savoir que deux classes ne doivent JAMAIS dépendre l'une de l'autre. C'est extrêmement important en C ++, et même si ce n'est pas la chose n ° 1 en Python, c'est toujours une très bonne idée de suivre cette règle. Jamais deux classes qui se connaissent, jamais. Si vous avez besoin d'aide pour créer la structure de vos classes, postez également le reste du code. Comment sont exactement (en termes de code) Entityet Physicsliés les uns aux autres? Je suis sûr qu'il existe une solution de contournement à ce que vous essayez de faire.
7
@ user2032433 Cela dépend vraiment de ce que vous entendez par «se connaître». Il est vrai qu'une bonne conception produit généralement un arbre de dépendances à sens unique et c'est normalement la meilleure approche. Mais il y a des exceptions à cela. Les classes C ++ peuvent certainement se référencer de façon circulaire. (Bien qu'il soit impossible qu'ils soient composés les uns des autres.) Sans déclaration directe, c'est un problème en Python qui n'a pas toujours de solution C ++.
John McFarlane
93
L'énoncé «deux classes ne doivent JAMAIS dépendre l'une de l'autre» est un déchet. La navigation bidirectionnelle (bidirectionnelle) est très courante dans l'orientation des objets. books.google.co.uk/…
Martin Spamer
5
Le modèle de conception State (par exemple) est généralement implémenté avec une classe Context et une interface State. Les instances d'État reçoivent l'instance de contexte pour pouvoir appeler setState. Cela nécessite que l'État connaisse le contexte et vice-versa. Comment cette construction classique est-elle "mauvaise au code"? En fait, c'est exactement le problème avec lequel je lutte en Python, mais ce n'était pas nécessaire lorsque j'ai implémenté State en Java.
Auspice
142

Alors que vous devez absolument éviter les dépendances circulaires, vous pouvez différer les importations en python.

par exemple:

import SomeModule

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

cela (au moins dans certains cas) contournera l'erreur.

bharling
la source
38
les dépendances circulaires sont mieux contournées
ckb
4
Baser sur pep8, mettre la méthode d'importation à l'intérieur n'est pas une bonne pratique
TomSawyer
@ TomSawyer Pourquoi?
Kröw
@ TomSawyer Je ne recommande pas cela, mais c'est une solution rapide qui peut vous sortir d'une
impasse
117

Il s'agit d'une dépendance circulaire. Il peut être résolu sans aucune modification structurelle du code. Le problème se produit parce que vectorvous exigez qu'il entitysoit rendu disponible immédiatement, et vice versa. La raison de ce problème est que vous demandez d'accéder au contenu du module avant qu'il ne soit prêt - en utilisant from x import y. C'est essentiellement le même que

import x
y = x.y
del x

Python est capable de détecter les dépendances circulaires et d'empêcher la boucle infinie des importations. Essentiellement, tout ce qui se passe est qu'un espace réservé vide est créé pour le module (c'est-à-dire qu'il n'a pas de contenu). Une fois les modules circulairement dépendants compilés, il met à jour le module importé. Cela fonctionne quelque chose comme ça.

a = module() # import a

# rest of module

a.update_contents(real_a)

Pour que python puisse fonctionner avec des dépendances circulaires, vous devez utiliser import xuniquement le style.

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

Puisque vous ne faites plus référence au contenu du module au niveau supérieur, python peut compiler le module sans avoir à accéder au contenu de la dépendance circulaire. Par niveau supérieur, j'entends les lignes qui seront exécutées pendant la compilation, par opposition au contenu des fonctions (par exemple. y = x.y). Les variables statiques ou de classe accédant au contenu du module causeront également des problèmes.

Dunes
la source
24

Il est très important de clarifier la logique. Ce problème apparaît, car la référence devient une boucle morte.

Si vous ne voulez pas changer la logique, vous pouvez placer l'instruction some import qui a causé ImportError à l'autre position du fichier, par exemple la fin.

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

Vous obtiendrez une erreur d'importation: ImportError: cannot import name 'a1'

Mais si nous changeons la position de from test.b import b2 in A comme ci-dessous:

a.py

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

from test.b import b2

Et nous pouvons obtenir ce que nous voulons:

b1
a1
b2
g10guang
la source
18

Il s'agit d'une dépendance circulaire. nous pouvons résoudre ce problème en utilisant le module ou la classe d' importation ou la fonction là où nous en avions besoin. si nous utilisons cette approche, nous pouvons corriger la dépendance circulaire

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
la source
17

Je viens de recevoir cette erreur aussi, pour une raison différente ...

from my_sub_module import my_function

Le script principal avait des fins de ligne Windows. my_sub_moduleavait des fins de ligne UNIX. Les changer pour être les mêmes a résolu le problème. Ils doivent également avoir le même codage de caractères.

marengaz
la source
7

Comme déjà mentionné, cela est dû à une dépendance circulaire . Ce qui n'a pas été mentionné, c'est que lorsque vous utilisez un module de typage Python et que vous importez une classe uniquement pour être utilisée pour annoter des types , vous pouvez utiliser des références Forward :

Lorsqu'un indice de type contient des noms qui n'ont pas encore été définis, cette définition peut être exprimée sous la forme d'un littéral de chaîne, à résoudre ultérieurement.

et supprimer la dépendance (l' importation ), par exemple au lieu de

from my_module import Tree

def func(arg: Tree):
    # code

faire:

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

(notez la importdéclaration supprimée )

Tomasz Bartkowiak
la source
6

Ne nommez pas votre script python actuel avec le nom d'un autre module que vous importez

Lösung: renommez votre manuscrit de python fonctionnant

Exemple:

  1. vous travaillez dans medicaltorch.py
  2. dans ce script, vous avez: from medicaltorch import datasets as mt_datasetsmedicaltorchest censé être un module installé

Cela échouera avec le ImportError. Renommez simplement votre script python de travail en 1.

Paul
la source
Merci, cela résout le problème que j'avais. J'ai utilisé la bibliothèque colorama et nommé le fichier colorama.py, donc python ne savait pas quoi importer. Changer le nom du fichier aide.
Marek Bodziony
5

Ne voyez pas encore celui-ci ici - c'est incroyablement stupide, mais assurez-vous d'importer la bonne variable / fonction.

Je recevais cette erreur

ImportError: impossible d'importer le nom IMPLICIT_WAIT

parce que ma variable était en fait IMPLICIT_TIMEOUT.

lorsque j'ai changé mon importation pour utiliser le nom correct, je n'ai plus d'erreur 🤦‍♂️

Nick Brady
la source
1
J'étais prêt à tuer quelqu'un essayant de comprendre pourquoi from PIL import Pillowne fonctionnait pas. 😠
aalaap
5

Si vous importez à file1.pypartir file2.pyet utilisé ceci:

if __name__ == '__main__':
    # etc

Les variables ci - dessous que file1.py ne peuvent pas être importés à file2.pycause __name__ ne est pas égal __main__ !

Si vous souhaitez importer quelque chose de file1.pyà file2.py, vous devez l'utiliser dans file1.py:

if __name__ == 'file1':
    # etc

En cas de doute, faites une assertdéclaration pour déterminer si__name__=='__main__'

Nicolas Gervais
la source
4

Une façon de suivre l'erreur d'importation consiste à essayer pas à pas d'exécuter python sur chacun des fichiers importés pour en rechercher le mauvais.

  1. vous obtenez quelque chose comme:

    python ./main.py

    ImportError: impossible d'importer le nom A

  2. puis vous lancez:

    python ./modules/a.py

    ImportError: impossible d'importer le nom B

  3. puis vous lancez:

    python ./modules/b.py

    ImportError: impossible d'importer le nom C (certains modules NON existants ou une autre erreur)

Evalds Urtans
la source
3

Également pas directement pertinent pour l'OP, mais le fait de ne pas redémarrer une console PyCharm Python, après avoir ajouté un nouvel objet à un module, est également un excellent moyen d'obtenir un très déroutantImportError: Cannot import name ...

La partie déroutante est que PyCharm terminera automatiquement l'importation dans la console, mais l'importation échoue ensuite.

djvg
la source
2

Le problème est clair: dépendance circulaire entre les noms entityet les physicsmodules.

Indépendamment de l'importation de l'ensemble du module ou d'une classe, les noms doivent être chargés.

Regardez cet exemple:

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

Cela sera compilé en:

# 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!

Avec un léger changement, nous pouvons résoudre ce problème:

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

Cela sera compilé en:

# 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
la source
2

Dans mon cas, je travaillais dans un cahier Jupyter et cela se produisait en raison de l'importation déjà mise en cache depuis que j'avais défini la classe / fonction dans mon fichier de travail.

J'ai redémarré mon noyau Jupyter et l'erreur a disparu.

Harry M
la source
1

Pas spécifiquement pour ce demandeur, mais cette même erreur s'affichera si le nom de classe dans votre importation ne correspond pas à la définition dans le fichier à partir duquel vous importez.

Bennett
la source