Disons que j'ai la structure de répertoire suivante:
a\
__init__.py
b\
__init__.py
c\
__init__.py
c_file.py
d\
__init__.py
d_file.py
Dans le __init__.py
du package a
, le package c
est importé. Mais c_file.py
importe a.b.d
.
Le programme échoue, indiquant que b
n'existe pas lorsque c_file.py
tente d'importer a.b.d
. (Et ça n'existe pas vraiment, parce que nous étions en train de l'importer.)
Comment résoudre ce problème?
Si a dépend de c et c dépend de a, ne sont-ils pas la même unité alors?
Vous devriez vraiment examiner pourquoi vous avez scindé a et c en deux packages, soit parce que vous avez du code que vous devez scinder en un autre package (pour que les deux dépendent de ce nouveau package, mais pas l'un de l'autre), ou vous devez les fusionner. en un seul paquet.
Vous pouvez différer l'importation, par exemple dans a/__init__.py
:
def my_function():
from a.b.c import Blah
return Blah()
c'est-à-dire, différer l'importation jusqu'à ce que cela soit vraiment nécessaire. Cependant, j'examinerais également de près mes définitions/utilisations de paquetages, car une dépendance cyclique comme celle qui est indiquée pourrait indiquer un problème de conception.
Je me suis posé cette question plusieurs fois (généralement lorsqu'il s'agit de modèles qui doivent se connaître). La solution simple consiste à importer l'ensemble du module, puis à référencer ce dont vous avez besoin.
Donc au lieu de faire
from models import Student
dans un, et
from models import Classroom
dans l'autre, il suffit de faire
import models
dans l'un d'eux, appelez ensuite models.Classroom quand vous en avez besoin.
Le problème est que lors de l'exécution à partir d'un répertoire, par défaut, seuls les packages qui sont des sous-répertoires sont visibles en tant qu'importations candidates. Vous ne pouvez donc pas importer a.b.d. Vous pouvez cependant importer b.d. puisque b est un sous-paquet de a.
Si vous voulez vraiment importer a.b.d dans c/__init__.py
, vous pouvez le faire en modifiant le chemin système en un répertoire au-dessus de a et en modifiant l'importation dans a/__init__.py
en importation a.b.c.
Votre a/__init__.py
devrait ressembler à ceci:
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
Une difficulté supplémentaire se pose lorsque vous souhaitez exécuter des modules en c en tant que scripts. Ici les paquets a et b n'existent pas. Vous pouvez pirater le __int__.py
dans le répertoire c pour qu'il pointe vers sys.path vers le répertoire de niveau supérieur, puis importer __init__
dans n’importe quel module de c pour pouvoir utiliser le chemin complet d’importation a.b.d. Je doute que ce soit une bonne pratique d'importer __init__.py
mais cela a fonctionné pour mes cas d'utilisation.
Je suggère le modèle suivant. Son utilisation permettra la complétion automatique et le repérage de type pour fonctionner correctement.
cyclic_import_a.py
import playground.cyclic_import_b
class A(object):
def __init__(self):
pass
def print_a(self):
print('a')
if __== '__main__':
a = A()
a.print_a()
b = playground.cyclic_import_b.B(a)
b.print_b()
cyclic_import_b.py
import playground.cyclic_import_a
class B(object):
def __init__(self, a):
self.a: playground.cyclic_import_a.A = a
def print_b(self):
print('b1-----------------')
self.a.print_a()
print('b2-----------------')
Vous ne pouvez pas importer les classes A et B en utilisant cette syntaxe
from playgroud.cyclic_import_a import A
from playground.cyclic_import_b import B
Vous ne pouvez pas déclarer le type de paramètre a dans la méthode B de classe B __ init __, mais vous pouvez le "transtyper" de cette façon:
def __init__(self, a):
self.a: playground.cyclic_import_a.A = a