guia - Dependencia de importación circular en Python
guia qgis (5)
El problema es que cuando se ejecuta desde un directorio, de manera predeterminada, solo los paquetes que son subdirectorios son visibles como importaciones candidatas, por lo que no puede importar abd. Sin embargo, puede importar bd ya que b es un subpaquete de a.
Si realmente quieres importar abd en c/__init__.py
, puedes lograr esto cambiando la ruta del sistema para que sea un directorio arriba de a y cambiar la importación en a/__init__.py
para importar abc
Tu a/__init__.py
debería verse así:
import sys
import os
# set sytem path to be directory above so that a can be a
# package namespace
DIRECTORY_SCRIPT = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0,DIRECTORY_SCRIPT+"/..")
import a.b.c
Se presenta una dificultad adicional cuando desea ejecutar módulos en c como scripts. Aquí los paquetes a y b no existen. Puede hackear __int__.py
en el directorio c para apuntar sys.path al directorio de nivel superior y luego importar __init__
en cualquier módulo dentro de c para poder usar la ruta completa para importar abd. Dudo que sea una buena práctica para importar __init__.py
pero ha funcionado para mis casos de uso.
Digamos que tengo la siguiente estructura de directorio:
a/
__init__.py
b/
__init__.py
c/
__init__.py
c_file.py
d/
__init__.py
d_file.py
En el __init__.py
a
paquete, se __init__.py
el paquete c
. Pero c_file.py
importa abd
.
El programa falla, diciendo que b
no existe cuando c_file.py
intenta importar abd
. (Y realmente no existe, porque estábamos en el medio de importarlo).
¿Cómo se puede remediar este problema?
Me lo he preguntado un par de veces (por lo general, cuando trato con modelos que necesitan saber el uno del otro). La solución simple es solo importar todo el módulo, luego hacer referencia a lo que necesita.
Entonces, en lugar de hacer
from models import Student
en uno, y
from models import Classroom
en el otro, solo hazlo
import models
en uno de ellos, luego llama a los modelos.Aula cuando lo necesites.
Otra solución es usar un proxy para el d_file.
Por ejemplo, supongamos que quieres compartir la clase blah con el c_file. El d_file por lo tanto contiene:
class blah:
def __init__(self):
print("blah")
Esto es lo que ingresas en c_file.py:
# do not import the d_file !
# instead, use a place holder for the proxy of d_file
# it will be set by a''s __init__.py after imports are done
d_file = None
def c_blah(): # a function that calls d_file''s blah
d_file.blah()
Y en init init .py:
from b.c import c_file
from b.d import d_file
class Proxy(object): # module proxy
pass
d_file_proxy = Proxy()
# now you need to explicitly list the class(es) exposed by d_file
d_file_proxy.blah = d_file.blah
# finally, share the proxy with c_file
c_file.d_file = d_file_proxy
# c_file is now able to call d_file.blah
c_file.c_blah()
Puede diferir la importación, por ejemplo, en a/__init__.py
:
def my_function():
from a.b.c import Blah
return Blah()
es decir, postergar la importación hasta que realmente se necesite. Sin embargo, también vería de cerca las definiciones / usos de mi paquete, ya que una dependencia cíclica como la señalada podría indicar un problema de diseño.
Si a depende de c y c depende de a, ¿no son en realidad la misma unidad?
Deberías examinar realmente por qué has dividido ayc en dos paquetes, porque o tienes algún código que debes dividir en otro paquete (para que ambos dependan de ese nuevo paquete, pero no el uno para el otro), o deberías unirlos en un paquete