¿Qué puedo hacer con “ImportError: no se puede importar el nombre X” o “AttributeError: … (probablemente debido a una importación circular)”?

8 minutos de lectura

avatar de usuario
jvende

Tengo un código repartido en varios archivos que intentan import entre sí, de la siguiente manera:

principal.py:

from entity import Ent

entidad.py:

from physics import Physics
class Ent:
    ...

física.py:

from entity import Ent
class Physics:
    ...

entonces corro de main.py y me sale 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

Supongo que el error se debe a la importación. entity dos veces – una vez en main.py y más tarde en physics.py – pero ¿cómo puedo solucionar el problema?


Consulte también ¿Qué sucede cuando se usan importaciones mutuas o circulares (cíclicas) en Python? para obtener una descripción general de lo que está permitido y lo que causa un problema con las importaciones circulares WRT. Consulte ¿Por qué las importaciones circulares aparentemente funcionan más arriba en la pila de llamadas pero luego generan un ImportError más abajo? para detalles técnicos sobre porque y como se produce el problema.

  • ¿Cuál es la estructura de directorios donde se almacenan y en qué directorios?

    – ben

    12 de febrero de 2012 a las 20:56

  • eche un vistazo a esta respuesta para la importación de bucles en python: stackoverflow.com/questions/7199466/…

    – Gregorio

    12 de febrero de 2012 a las 20:56


  • En general, no es una buena práctica de codificación hacer 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

    12 de febrero de 2012 a las 20:57

  • @jsells Deberías llamar a tus clases Entity y Vector en vez de Ent y Vect, no hay razón para acortar esos nombres. Y si, usa import vector y entonces x = vector.Vector(0,0,0).

    usuario2032433

    18/04/2013 a las 17:00


  • Hola, @Kevin, ya que conoces Java mejor, ¿cuál es tu impresión de esto? 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?

    – Oye, mira esto

    8 mayo 2014 a las 20:52


avatar de usuario
Teemu Ikonen

Tiene importaciones circulares dependientes. physics.py es importado de entity antes de clase Ent se define y physics intenta importar entity que ya se está inicializando. Eliminar la dependencia de physics de entity módulo.

  • No hay mucho que pueda hacer más que refactorizar su código. Si no hace referencia a Física en la definición del constructor de 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

    13 de febrero de 2012 a las 7:22

  • @jsells Como ha trabajado con C++ “durante mucho tiempo”, debe saber que dos clases NUNCA deben depender entre sí. Esto es extremadamente importante en C++, e incluso si no es lo primero en Python, sigue siendo una muy buena idea seguir esta regla. Nunca tengas 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 son exactamente (en términos de código) Entity y Physics ¿vinculados entre sí? Estoy seguro de que hay una solución para lo que estás tratando de hacer.

    usuario2032433

    18 de abril de 2013 a las 17:03


  • @ user2032433 Eso realmente depende de lo que quieras decir con ‘conocerse’. Es cierto que un buen diseño generalmente produce un árbol de dependencias unidireccionales y este suele ser el mejor enfoque. Pero hay excepciones a esto. Las clases de C++ ciertamente pueden referirse entre sí circularmente. (Aunque es imposible que estén compuestos uno del otro). Sin una declaración directa, este es un problema en Python que no siempre tiene una solución en C++.

    – John MacFarlane

    3 de junio de 2014 a las 19:14

  • La declaración “dos clases NUNCA deben depender 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/…

    – Martín Spamer

    17 dic 2014 a las 17:38

  • 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 State se pasan a la instancia de Context para que puedan llamar a setState. Esto requiere que el Estado conozca el Contexto y viceversa. ¿Cómo es que esta construcción clásica es “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

    1 de diciembre de 2017 a las 20:17

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.

  • las dependencias circulares se eluden mejor

    – ckb

    08/07/2016 a las 21:27

  • Basado en pep8, poner el método import inside no es una buena práctica

    – Tom Sawyer

    10 mayo 2019 a las 17:29

  • @TomSawyer ¿Por qué?

    – Krow

    3 de noviembre de 2019 a las 7:41

  • @TomSawyer No recomiendo esto, pero es una solución rápida que puede sacarlo de un apuro

    – bharling

    11 mayo 2020 a las 21:24

  • @bharling, ¿puedes explicar un poco más? esta fue una solución fuerte para mí

    – ido

    3 jun a las 22:23

avatar de usuario
Dunas

Esta es una dependencia circular. Se puede resolver sin modificaciones estructurales al código. El problema ocurre porque en vector tu exiges eso entity estar disponible para su uso inmediato, y viceversa. El motivo de este problema es que solicita acceder al contenido del módulo antes de que esté listo, utilizando from x import y. Esto es esencialmente lo mismo que

import x
y = x.y
del x

Python es capaz de 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 circularmente dependientes, 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 x solo estilo.

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

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

  • Esta respuesta es importante y una solución más general para otros. Tenga en cuenta que si está importando un submódulo local (es decir, import app.foo.bar) necesita darle un nombre (es decir import app.foo.bar as bar)

    – princesa de datos

    28 de julio de 2020 a las 21:48

En mi caso, estaba trabajando en un cuaderno Jupyter y esto sucedía debido a que la importación ya estaba en caché desde que definí la clase/función dentro de mi archivo de trabajo.

Reinicié mi kernel Jupyter y el error desapareció.

Aclarar la lógica es muy importante. Este problema aparece porque la referencia se convierte en un bucle muerto.

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á un error de importación: ImportError: cannot import name 'a1'

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

a.py

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

from test.b import b2

Y podemos obtener lo que queremos:

b1
a1
b2

avatar de usuario
Ankit Patidar

Esta es una dependencia circular. podemos resolver este problema usando importar módulo o clase o función donde necesitábamos. 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() 

Acabo de recibir este error también, por una razón diferente …

from my_sub_module import my_function

El guión principal tenía terminaciones de línea de Windows. my_sub_module tenía terminaciones de línea UNIX. Cambiarlos para que sean iguales solucionó el problema. También deben tener la misma codificación de caracteres.

¿Ha sido útil esta solución?