Si encuentras alguna parte que no comprendes puedes dejarlo en la sección de comentarios y te ayudaremos tan rápido como podamos.
Solución:
Considere el siguiente paquete de Python de ejemplo donde a.py
y b.py
dependen unos de otros:
/package
__init__.py
a.py
b.py
Tipos de problemas de importación circular
Las dependencias de importación circular generalmente se dividen en dos categorías según lo que intente importar y dónde lo use dentro de cada módulo. (Y si está usando Python 2 o 3).
1. Errores al importar módulos con importaciones circulares
En algunos casos, simplemente importador un módulo con una dependencia de importación circular puede generar errores incluso si no hace referencia a nada del módulo importado.
Hay varias formas estándar de importar un módulo en python
import package.a # (1) Absolute import
import package.a as a_mod # (2) Absolute import bound to different name
from package import a # (3) Alternate absolute import
import a # (4) Implicit relative import (deprecated, python 2 only)
from . import a # (5) Explicit relative import
Desafortunadamente, solo las opciones 1 y 4 funcionan cuando tiene dependencias circulares (el resto genera ImportError
o AttributeError
). En general, no debería usar la cuarta sintaxis, ya que solo funciona en python2 y corre el riesgo de entrar en conflicto con otros módulos de terceros. Entonces, realmente, solo se garantiza que funcione la primera sintaxis.
EDITAR: El
ImportError
yAttributeError
los problemas solo ocurren en python 2. En python 3, la maquinaria de importación se ha reescrito y todas estas declaraciones de importación (con la excepción de 4) funcionarán, incluso con dependencias circulares. Si bien las soluciones de esta sección pueden ayudar a refactorizar el código de Python 3, están destinadas principalmente a las personas que usan Python 2.
Importación absoluta
Simplemente use la primera sintaxis de importación anterior. La desventaja de este método es que los nombres de importación pueden obtener súper largo para paquetes grandes.
En a.py
import package.b
En b.py
import package.a
Aplazar la importación hasta más tarde
He visto este método utilizado en muchos paquetes, pero todavía me parece raro, y no me gusta que no pueda mirar en la parte superior de un módulo y ver todas sus dependencias, tengo que buscar en todas las funciones. así como.
En a.py
def func():
from package import b
En b.py
def func():
from package import a
Ponga todas las importaciones en un módulo central
Esto también funciona, pero tiene el mismo problema que el primer método, donde todas las llamadas de paquetes y submódulos se obtienen súper largo. También tiene dos defectos importantes: obliga a todos los submódulos para ser importado, incluso si solo está usando uno o dos, y todavía no puede mirar ninguno de los submódulos y ver rápidamente sus dependencias en la parte superior, tiene que examinar las funciones.
En __init__.py
from . import a
from . import b
En a.py
import package
def func():
package.b.some_object()
En b.py
import package
def func():
package.a.some_object()
2. Errores al usar objetos importados con dependencias circulares
Ahora, si bien es posible que pueda importar un módulo con una dependencia de importación circular, no podrá importar ningún objeto definido en el módulo ni podrá hacer referencia a ese módulo importado en ninguna parte del nivel superior del módulo donde lo está importando. Sin embargo, puede utilizar el módulo importado en el interior funciones y bloques de código que no se ejecutan en la importación.
Por ejemplo, esto funcionará:
paquete/a.py
import package.b
def func_a():
return "a"
paquete/b.py
import package.a
def func_b():
# Notice how package.a is only referenced *inside* a function
# and not the top level of the module.
return package.a.func_a() + "b"
Pero esto no funcionará
paquete/a.py
import package.b
class A(object):
pass
paquete/b.py
import package.a
# package.a is referenced at the top level of the module
class B(package.a.A):
pass
obtendrá una excepción
AttributeError: el módulo ‘paquete’ no tiene attribute ‘a’
Generalmente, en la mayoría de los casos válidos de dependencias circulares, es posible refactorizar o reorganizar el código para evitar estos errores y mover las referencias del módulo dentro de un bloque de código.
Solo importe el módulo, no importe desde el módulo:
Considerar a.py
:
import b
class A:
def bar(self):
return b.B()
y b.py
:
import a
class B:
def bar(self):
return a.A()
Esto funciona perfectamente bien.
Hacemos una combinación de funciones e importaciones absolutas para una mejor lectura y cadenas de acceso más cortas.
- Ventaja: cadenas de acceso más cortas en comparación con las importaciones absolutas puras
- Desventaja: un poco más de sobrecarga debido a la llamada de función adicional
principal/sub/a.py
import main.sub.b
b_mod = lambda: main.sub.b
class A():
def __init__(self):
print('in class "A":', b_mod().B.__name__)
principal/sub/b.py
import main.sub.a
a_mod = lambda: main.sub.a
class B():
def __init__(self):
print('in class "B":', a_mod().A.__name__)
Acuérdate de que tienes la opción de añadir una evaluación justa .