ImportError: no se puede importar el nombre X


540

Tengo cuatro archivos diferentes llamados: principal, vector, entidad y física. No publicaré todo el código, solo las importaciones, porque creo que ahí es donde está el error. (Si quieres, puedo publicar más)

Principal:

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

Entidad:

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

Vector:

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

Física:

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

Luego ejecuto desde main.py y aparece el siguiente error:

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

Soy muy nuevo en Python pero he trabajado con C ++ durante mucho tiempo. Supongo que el error se debe a la importación de la entidad dos veces, una vez en main y luego en física, pero no conozco una solución alternativa. ¿Alguien puede ayudar?


¿Cuál es la estructura de directorios de dónde están almacenados y en qué directorios?
Ben

1
eche un vistazo a esta respuesta para importar bucles en python: stackoverflow.com/questions/7199466/…
Gregor

En general, no es una buena práctica de codificación from <module> import <name>, o from <modlue> import *. Es mejor importar bajo el espacio de nombres del módulo para evitar la posibilidad de sobrescribir referencias con nombres idénticos.
Joel Cornett

1
@jsells Deberías llamar a tus clases Entityy en Vectorlugar deEnt y Vect, no hay razón para acortar esos nombres. Y sí, usa import vectory luego x = vector.Vector(0,0,0).

77
Hola @Kevin, ya que conoces Java mejor, ¿cuál es tu impresión de este artículo de 2008 donde la primera oración del autor se refiere a cómo las dependencias circulares son "práctica bastante común" en Java?
Hola

Respuestas:


503

Tiene importaciones circulares dependientes. physics.pyse importa deentity antes de que Entse defina la clase e physicsintenta importar entityque ya se está inicializando. Elimine la dependencia de physicsdel entitymódulo.


55
No hay mucho que pueda hacer que refactorizar su código. Si no hace referencia a la definición del constructor Física en Ent, mueva mport justo debajo de Ent. Si lo hace, agregue un método como setPhysics para habilitar la importación después del constructor.
Teemu Ikonen

12
@jsells Dado que ha trabajado con C ++ "durante mucho tiempo", debe saber que dos clases NUNCA deberían depender la una de la otra. Esto es extremadamente importante en C ++, e incluso si no es la cosa # 1 en Python, sigue siendo una muy buena idea seguir esta regla. Nunca tenga dos clases que se conozcan, nunca. Si necesita ayuda para crear la estructura de sus clases, publique también el resto del código. ¿Cómo funciona exactamente (en términos de código) están Entityy Physicsvinculados entre sí? Estoy seguro de que hay una solución para lo que estás tratando de hacer.

77
@ user2032433 Eso realmente depende de lo que quiere decir con 'conocerse'. Es cierto que un buen diseño generalmente produce un árbol de dependencias unidireccionales y este es normalmente el mejor enfoque. Pero hay excepciones a esto. Las clases de C ++ ciertamente pueden referirse entre sí de forma circular. (Aunque es imposible que se compongan unos de otros). Sin la declaración directa, este es un problema en Python que no siempre tiene una solución C ++.
John McFarlane

93
La afirmación "dos clases NUNCA deberían depender la una de la otra" es basura. La navegación bidireccional (bidireccional) es muy común en la orientación a objetos. books.google.co.uk/…
Martin Spamer

55
El patrón de diseño de estado (por ejemplo) generalmente se implementa con una clase de contexto y una interfaz de estado. Las instancias de estado pasan la instancia de contexto para que puedan llamar a setState. Esto requiere que el Estado sepa sobre el contexto y viceversa. ¿Cómo es esta construcción clásica siendo "mala en el código"? En realidad, ese es exactamente el problema con el que estoy luchando en Python, pero no tuve que hacerlo cuando implementé State en Java.
Auspicio

142

Si bien definitivamente debe evitar las dependencias circulares, puede diferir las importaciones en python.

por ejemplo:

import SomeModule

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

esto (al menos en algunos casos) evitará el error.


38
las dependencias circulares se eluden mejor
ckb

44
Base en pep8, poner importación dentro del método no es una buena práctica
TomSawyer

@TomSawyer ¿Por qué?
Kröw

@TomSawyer No recomiendo esto, pero es una solución rápida que puede
sacarte de apuros

117

Esta es una dependencia circular. Se puede resolver sin modificaciones estructurales en el código. El problema se produce porque vectorusted exige que entityesté disponible para su uso inmediato, y viceversa. La razón de este problema es que usted solicita acceder al contenido del módulo antes de que esté listo, mediante el uso from x import y. Esto es esencialmente lo mismo que

import x
y = x.y
del x

Python puede detectar dependencias circulares y evitar el ciclo infinito de importaciones. Esencialmente, todo lo que sucede es que se crea un marcador de posición vacío para el módulo (es decir, no tiene contenido). Una vez que se compilan los módulos dependientes circularmente, actualiza el módulo importado. Esto funciona algo como esto.

a = module() # import a

# rest of module

a.update_contents(real_a)

Para que Python pueda trabajar con dependencias circulares, debe usar import xsolo estilo.

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

Como ya no se está refiriendo a los contenidos del módulo en el nivel superior, python puede compilar el módulo sin tener que acceder a los contenidos de la dependencia circular. Por nivel superior me refiero a las líneas que se ejecutarán durante la compilación en lugar de los contenidos de las funciones (por ejemplo y = x.y). Las variables estáticas o de clase que acceden al contenido del módulo también causarán problemas.


24

Dejar la lógica clara es muy importante. Este problema aparece porque la referencia se convierte en un bucle inactivo.

Si no desea cambiar la lógica, puede colocar alguna declaración de importación que causó ImportError en la otra posición del archivo, por ejemplo, al final.

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

Obtendrá Error de importación: ImportError: cannot import name 'a1'

Pero si cambiamos la posición de test.b importamos b2 en A como a continuación:

a.py

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

from test.b import b2

Y podemos obtener lo que queremos:

b1
a1
b2

18

Esta es una dependencia circular. podemos resolver este problema usando import módulo de o clase o función donde lo necesitamos. si usamos este enfoque, podemos arreglar la dependencia circular

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

También recibí este error, por una razón diferente ...

from my_sub_module import my_function

El script principal tenía finales de línea de Windows. my_sub_moduletenía terminaciones de línea UNIX. Cambiarlos para que sean los mismos solucionó el problema. También necesitan tener la misma codificación de caracteres.


7

Como ya se mencionó, esto es causado por una dependencia circular . Lo que no se ha mencionado es que cuando usa el módulo de mecanografía Python e importa una clase solo para anotar Tipos , puede usar Reenviar referencias :

Cuando una sugerencia de tipo contiene nombres que aún no se han definido, esa definición puede expresarse como un literal de cadena, que se resolverá más adelante.

y eliminar la dependencia (la importación ), por ejemplo, en lugar de

from my_module import Tree

def func(arg: Tree):
    # code

hacer:

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

(tenga en cuenta la importdeclaración eliminada )


6

No nombre su script actual de Python con el nombre de algún otro módulo que importe

Solución: cambie el nombre de su script de Python en funcionamiento

Ejemplo:

  1. estas trabajando en medicaltorch.py
  2. en ese script, tienes: from medicaltorch import datasets as mt_datasetsdonde medicaltorchse supone que es un módulo instalado

Esto fallará con el ImportError. Simplemente cambie el nombre de su script de Python en funcionamiento en 1.


Gracias, esto resuelve el problema que tuve. Usé la biblioteca de colorama y llamé al archivo colorama.py, por lo que Python no sabía qué importar. Cambiar el nombre del archivo ayuda.
Marek Bodziony

5

Todavía no veo este aquí, esto es increíblemente estúpido, pero asegúrese de importar la variable / función correcta.

Estaba recibiendo este error

ImportError: no se puede importar el nombre IMPLICIT_WAIT

porque mi variable fue en realidad IMPLICIT_TIMEOUT.

cuando cambié mi importación para usar el nombre correcto, ya no recibí el error 🤦‍♂️


1
Estaba listo para matar a alguien tratando de entender por qué from PIL import Pillowno estaba funcionando. 😠
aalaap

5

Si va a importar file1.pydesde file2.pyy utilizó la siguiente:

if __name__ == '__main__':
    # etc

Las variables a continuación que en file1.py no se pueden importar a file2.pyporque __name__ no es igual __main__ !

Si desea importar algo de file1.pya file2.py, debe usar esto en file1.py:

if __name__ == 'file1':
    # etc

En caso de duda, haga una assertdeclaración para determinar si__name__=='__main__'


4

Una forma de rastrear el error de importación es, paso a paso, tratar de ejecutar Python en cada uno de los archivos importados para rastrear el malo.

  1. obtienes algo como:

    python ./main.py

    ImportError: no se puede importar el nombre A

  2. entonces lanzas:

    python ./modules/a.py

    ImportError: no se puede importar el nombre B

  3. entonces lanzas:

    python ./modules/b.py

    ImportError: no se puede importar el nombre C (algún módulo NO EXISTENTE u otro error)


3

Tampoco es directamente relevante para el OP, pero no reiniciar una consola PyCharm Python, después de agregar un nuevo objeto a un módulo, también es una excelente manera de obtener una muy confusaImportError: Cannot import name ...

La parte confuso es que PyCharm se completará automáticamente la importación en la consola, pero la importación a continuación, falla.


2

El problema es claro: dependencia circular entre los nombres entityy los physicsmódulos.

Independientemente de importar todo el módulo o solo una clase, los nombres deben cargarse.

Mira este ejemplo:

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

Esto se compilará 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!

Con un ligero cambio podemos resolver esto:

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

Esto se compilará 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!

2

En mi caso, estaba trabajando en una computadora portátil Jupyter y esto estaba sucediendo debido a que la importación ya estaba en caché cuando definí la clase / función dentro de mi archivo de trabajo.

Reinicié mi núcleo Jupyter y el error desapareció.


1

No específicamente para este autor de la pregunta, pero este mismo error se mostrará si el nombre de la clase en su importación no coincide con la definición en el archivo desde el que está importando.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.