Considérons l'exemple suivant de paquet python où a.py
y b.py
dépendent les uns des autres :
/package
__init__.py
a.py
b.py
Types de problèmes d'importation circulaire
Les dépendances circulaires à l'importation se répartissent généralement en deux catégories, selon qu'il s'agit de de ce que vous essayez d'importer et de l'endroit où vous l'utilisez dans chaque catégorie. module. (Et si vous utilisez Python 2 ou 3).
1. Erreurs lors de l'importation de modules avec des importations circulaires
Dans certains cas, il suffit de importation un module avec une dépendance d'importation circulaire peut entraîner des erreurs même si vous ne faites référence à rien dans le module importé. importé.
Il existe plusieurs façons d'importer un module 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
Malheureusement, seules les 1ère et 4ème options fonctionnent réellement lorsque vous dépendances circulaires (les autres options soulèvent toutes des ImportError
ou AttributeError
). En général, vous ne devriez pas utiliser la syntaxe 4ème syntaxe, puisqu'elle ne fonctionne qu'en python2 et qu'elle risque de d'entrer en conflit avec d'autres modules tiers. En réalité, seule la première syntaxe est garantie de fonctionner.
EDIT : Le ImportError
y AttributeError
Les problèmes ne se posent qu'en python 2. Dans Python 3, les mécanismes d'importation ont été réécrits et tous les (à l'exception de la 4) fonctionneront, même avec la commande dépendances circulaires. Bien que les solutions proposées dans cette section puissent aider à remanier les c aux personnes utilisant Python 2.
Importation absolue
Il suffit d'utiliser la première syntaxe d'importation ci-dessus. L'inconvénient de cette méthode est que les noms d'importation peuvent devenir super long pour les gros colis.
En a.py
import package.b
En b.py
import package.a
Reporter l'importation à plus tard
J'ai vu cette méthode utilisée dans de nombreux paquets, mais elle donne toujours l'impression d'avoir été utilisée par un grand nombre de personnes. hacky pour moi, et je n'aime pas le fait que je ne puisse pas regarder en haut d'un module et voir toutes ses dépendances, je dois chercher dans toutes les fonctions.
En a.py
def func():
from package import b
En b.py
def func():
from package import a
Placer toutes les importations dans un module central
Cette méthode fonctionne également, mais présente le même problème que la première méthode, à savoir que tous les appels de paquets et de sous-modules sont super long . Il dispose également de deux deux défauts majeurs : il oblige les tous les sous-modules à importer, même si vous n'en utilisez qu'un ou deux, et vous ne pouvez toujours pas consulter l'un ou l'autre des sous-modules et voir rapidement leurs dépendances en haut, vous devez passer au crible les fonctions.
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. Erreurs lors de l'utilisation d'objets importés avec des dépendances circulaires
Or, si vous pouvez importer une module avec une importation circulaire circulaire, vous ne pourrez pas importer les objets définis dans le module ni faire référence à ce module importé où que ce soit dans le niveau supérieur du module où vous l'importez. Vous pouvez, cependant, utiliser le module importé à l'intérieur les fonctions et les blocs de code qui ne sont pas pas exécutés lors de l'importation.
Par exemple, ceci fonctionnera :
package/a.py
import package.b
def func_a():
return "a"
package/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"
Mais cela ne fonctionnera pas
package/a.py
import package.b
class A(object):
pass
package/b.py
import package.a
# package.a is referenced at the top level of the module
class B(package.a.A):
pass
Vous obtiendrez une exception
AttributeError : le module "package" n'a pas d'attribut "a".
En règle générale, dans la plupart des cas de dépendances circulaires, il est possible de de refactoriser ou de réorganiser le code pour éviter ces erreurs et déplacer les les références aux modules à l'intérieur d'un bloc de code.