Maison développement back-end Tutoriel Python Différentes façons de corriger les importations circulaires en Python

Différentes façons de corriger les importations circulaires en Python

Nov 05, 2024 am 02:21 AM

Avez-vous déjà rencontré des importations circulaires en Python ? Eh bien, c'est une odeur de code très courante qui indique que quelque chose ne va pas avec la conception ou la structure.

Exemple d'importation circulaire

Comment se produit l'importation circulaire ? Cette erreur d'importation se produit généralement lorsque deux modules ou plus dépendant les uns des autres tentent d'importer avant de s'initialiser complètement.

Disons que nous avons deux modules : module_1.py et module_2.py.

# module_1.py
from module_2 import ModY
class ModX:
    mody_obj = ModY()
Copier après la connexion
Copier après la connexion
Copier après la connexion
# module_2.py
from module_1 import ModX
class ModY:
    modx_obj = ModX()
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans les extraits de code ci-dessus, module_1 et module_2 dépendent mutuellement l'un de l'autre.

L'initialisation de mody_obj dans module_1 dépend du module_2 et l'initialisation de modx_obj dans module_2 dépend du module_1.

C'est ce que nous appelons une dépendance circulaire. Les deux modules resteront bloqués dans les boucles d'importation lors de la tentative de chargement mutuel.

Si nous exécutons module_1.py, nous obtiendrons le traçage suivant.

Traceback (most recent call last):
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
  File "module_2.py", line 1, in <module>
    from module_1 import ModX
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
ImportError: cannot import name 'ModY' from partially initialized module 'module_2' (most likely due to a circular import)
Copier après la connexion
Copier après la connexion
Copier après la connexion

Cette erreur explique la situation de l'importation circulaire. Lorsque le programme a tenté d'importer ModY depuis module_2, à ce moment-là, module_2 n'était pas complètement initialisé (en raison d'une autre instruction d'importation qui tente d'importer ModX depuis module_1).

Comment réparer les importations circulaires en Python ? Il existe différentes façons de se débarrasser des importations circulaires en Python.

Corriger les importations circulaires en Python

Déplacer le code dans un fichier commun

Nous pouvons déplacer le code dans un fichier commun pour éviter les erreurs d'importation, puis essayer d'importer les modules à partir de ce fichier.

# main.py ----> common file
class ModX:
    pass

class ModY:
    pass
Copier après la connexion
Copier après la connexion

Dans l'extrait de code ci-dessus, nous avons déplacé les classes ModX et ModY dans un fichier commun (main.py).

# module_1.py
from main import ModY

class Mod_X:
    mody_obj = ModY()
Copier après la connexion
Copier après la connexion
# module_2.py
from main import ModX

class Mod_Y:
    modx_obj = ModX()
Copier après la connexion
Copier après la connexion

Maintenant, module_1 et module_2 importent les classes de main, ce qui corrige la situation d'importation circulaire.

Il y a un problème avec cette approche, parfois la base de code est si volumineuse qu'il devient risqué de déplacer le code dans un autre fichier.

Déplacer l'import à la fin du module

On peut décaler l'instruction import à la fin du module. Cela donnera le temps d'initialiser complètement le module avant d'importer un autre module.

# module_1.py
class ModX:
   pass

from module_2 import ModY

class Mod_X:
   mody_obj = ModY()
Copier après la connexion
Copier après la connexion
# module_2.py
class ModY:
   pass

from module_1 import ModX
Copier après la connexion
Copier après la connexion

Module d'importation dans la portée de la classe/fonction

L'importation de modules dans la portée de la classe ou de la fonction peut éviter les importations circulaires. Cela permet au module d'être importé uniquement lorsque la classe ou la fonction est invoquée. C'est pertinent lorsque nous voulons minimiser l'utilisation de la mémoire.

# module_1.py
class ModX:
  pass

class Mod_X:
   from module_2 import ModY
   mody_obj = ModY()
Copier après la connexion
Copier après la connexion
# module_2.py
class ModY:
   pass

class Mod_Y:
   from module_1 import ModX
   modx_obj = ModX()
Copier après la connexion
Copier après la connexion

Nous avons déplacé les instructions d'importation dans les classes Mod_X et Mod_Y respectivement dans module_1 et module_2.

Si nous exécutons module_1 ou module_2, nous n'obtiendrons pas d'erreur d'importation circulaire. Mais cette approche rend la classe accessible uniquement dans la portée de la classe, nous ne pouvons donc pas exploiter l’importation globalement.

Utilisation du nom/alias du module

Utiliser le nom du module ou simplement un alias comme celui-ci résout le problème. Cela permet aux deux modules de se charger complètement en différant la dépendance circulaire jusqu'à l'exécution.

# module_1.py
from module_2 import ModY
class ModX:
    mody_obj = ModY()
Copier après la connexion
Copier après la connexion
Copier après la connexion
# module_2.py
from module_1 import ModX
class ModY:
    modx_obj = ModX()
Copier après la connexion
Copier après la connexion
Copier après la connexion

Utilisation de la bibliothèque importlib

On peut également utiliser la bibliothèque importlib pour importer les modules dynamiquement.

Traceback (most recent call last):
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
  File "module_2.py", line 1, in <module>
    from module_1 import ModX
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
ImportError: cannot import name 'ModY' from partially initialized module 'module_2' (most likely due to a circular import)
Copier après la connexion
Copier après la connexion
Copier après la connexion
# main.py ----> common file
class ModX:
    pass

class ModY:
    pass
Copier après la connexion
Copier après la connexion

Importations circulaires dans les packages Python

Habituellement, les importations circulaires proviennent de modules au sein du même package. Dans les projets complexes, la structure des répertoires est également complexe, avec des packages dans les packages.

Ces packages et sous-packages contiennent des fichiers __init__.py pour faciliter l'accès aux modules. C'est là que surgissent parfois involontairement des dépendances circulaires entre les modules.

Nous avons la structure de répertoires suivante.

# module_1.py
from main import ModY

class Mod_X:
    mody_obj = ModY()
Copier après la connexion
Copier après la connexion

Nous avons un package mainpkg et un fichier main.py. Nous avons deux sous-packages modpkg_x et modpkg_y dans mainpkg.

Voici à quoi ressemble chaque fichier Python dans modpkg_x et modpkg_y.

mainpkg/modpkg_x/__init__.py

# module_2.py
from main import ModX

class Mod_Y:
    modx_obj = ModX()
Copier après la connexion
Copier après la connexion

Ce fichier importe les deux classes (ModX et ModA) de module_1 et module_1_1.

mainpkg/modpkg_x/module_1.py

# module_1.py
class ModX:
   pass

from module_2 import ModY

class Mod_X:
   mody_obj = ModY()
Copier après la connexion
Copier après la connexion

Le module_1 importe une classe ModY du module_2.

mainpkg/modpkg_x/module_1_1.py

# module_2.py
class ModY:
   pass

from module_1 import ModX
Copier après la connexion
Copier après la connexion

Le module_1_1 n'importe rien. Il ne dépend d'aucun module.

mainpkg/modpkg_y/__init__.py

# module_1.py
class ModX:
  pass

class Mod_X:
   from module_2 import ModY
   mody_obj = ModY()
Copier après la connexion
Copier après la connexion

Ce fichier importe la classe ModY du module_2.

mainpkg/modpkg_y/module_2.py

# module_2.py
class ModY:
   pass

class Mod_Y:
   from module_1 import ModX
   modx_obj = ModX()
Copier après la connexion
Copier après la connexion

Le module_2 importe une classe ModA du module_1_1.

Nous avons le code suivant dans le fichier main.py.

root_dir/main.py

# module_1.py
import module_2 as m2

class ModX:
    def __init__(self):
        self.mody_obj = m2.ModY()
Copier après la connexion

Le fichier principal importe une classe ModY du module_2. Ce fichier dépend du module_2.

Si nous visualisons le cycle d'importation ici, cela ressemblerait à ce qui suit en ignorant les fichiers __init__.py dans modpkg_x et modpkg_y.

Different Ways to Fix Circular Imports in Python

On voit que le fichier principal dépend du module_2, le module_1 dépend également du module_2 et le module_2 dépend du module_1_1. Il n'y a pas de cycle d'importation.

Mais vous savez, les modules dépendent de leur fichier __init__.py, donc le fichier __init__.py s'initialise en premier et les modules sont réimportés.

Different Ways to Fix Circular Imports in Python

Voici à quoi ressemble le cycle d'importation maintenant.

Different Ways to Fix Circular Imports in Python

Cela rendait module_1_1 dépendant de module_1, qui est une fausse dépendance.

Si tel est le cas, videz les fichiers __init__.py des sous-packages et l'utilisation d'un fichier __init__.py distinct peut aider en centralisant les importations au niveau du package.

# module_1.py
from module_2 import ModY
class ModX:
    mody_obj = ModY()
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans cette structure, nous avons ajouté un autre sous-paquet subpkg dans mainpkg.

mainpkg/subpkg/__init__.py

# module_2.py
from module_1 import ModX
class ModY:
    modx_obj = ModX()
Copier après la connexion
Copier après la connexion
Copier après la connexion

Cela permettra aux modules internes d'importer à partir d'une source unique, réduisant ainsi le besoin d'importations croisées.

Nous pouvons maintenant mettre à jour l'instruction d'importation dans le fichier main.py.

root_dir/main.py

Traceback (most recent call last):
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
  File "module_2.py", line 1, in <module>
    from module_1 import ModX
  File "module_1.py", line 1, in <module>
    from module_2 import ModY
ImportError: cannot import name 'ModY' from partially initialized module 'module_2' (most likely due to a circular import)
Copier après la connexion
Copier après la connexion
Copier après la connexion

Cela résout le problème de dépendance circulaire entre les modules au sein d'un même package.

Conclusion

La dépendance circulaire ou l'importation en Python est une odeur de code qui est une indication d'une restructuration et d'une refactorisation sérieuses du code.

Vous pouvez essayer l'une des méthodes mentionnées ci-dessus pour éviter les dépendances circulaires en Python.


?D'autres articles qui pourraient vous intéresser si celui-ci vous a plu

✅Héritage de modèles dans Flask avec exemple.

✅Différence entre exec() et eval() avec exemples.

✅Comprendre l'utilisation du mot-clé global en Python.

✅Conseils sur le type Python : fonctions, valeurs de retour, variable.

✅Pourquoi la barre oblique et l'astérisque sont utilisés dans la définition des fonctions.

✅Comment le taux d'apprentissage affecte-t-il les modèles ML et DL ?


C'est tout pour le moment.

Continuez à coder✌✌.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Comment résoudre le problème des autorisations rencontré lors de la visualisation de la version Python dans le terminal Linux? Comment résoudre le problème des autorisations rencontré lors de la visualisation de la version Python dans le terminal Linux? Apr 01, 2025 pm 05:09 PM

Solution aux problèmes d'autorisation Lors de la visualisation de la version Python dans Linux Terminal Lorsque vous essayez d'afficher la version Python dans Linux Terminal, entrez Python ...

Comment éviter d'être détecté par le navigateur lors de l'utilisation de Fiddler partout pour la lecture de l'homme au milieu? Comment éviter d'être détecté par le navigateur lors de l'utilisation de Fiddler partout pour la lecture de l'homme au milieu? Apr 02, 2025 am 07:15 AM

Comment éviter d'être détecté lors de l'utilisation de FiddlereVerywhere pour les lectures d'homme dans le milieu lorsque vous utilisez FiddlereVerywhere ...

Comment copier efficacement la colonne entière d'une dataframe dans une autre dataframe avec différentes structures dans Python? Comment copier efficacement la colonne entière d'une dataframe dans une autre dataframe avec différentes structures dans Python? Apr 01, 2025 pm 11:15 PM

Lorsque vous utilisez la bibliothèque Pandas de Python, comment copier des colonnes entières entre deux frames de données avec différentes structures est un problème courant. Supposons que nous ayons deux dats ...

Comment Uvicorn écoute-t-il en permanence les demandes HTTP sans servir_forever ()? Comment Uvicorn écoute-t-il en permanence les demandes HTTP sans servir_forever ()? Apr 01, 2025 pm 10:51 PM

Comment Uvicorn écoute-t-il en permanence les demandes HTTP? Uvicorn est un serveur Web léger basé sur ASGI. L'une de ses fonctions principales est d'écouter les demandes HTTP et de procéder ...

Comment enseigner les bases de la programmation novice en informatique dans le projet et les méthodes axées sur les problèmes dans les 10 heures? Comment enseigner les bases de la programmation novice en informatique dans le projet et les méthodes axées sur les problèmes dans les 10 heures? Apr 02, 2025 am 07:18 AM

Comment enseigner les bases de la programmation novice en informatique dans les 10 heures? Si vous n'avez que 10 heures pour enseigner à l'informatique novice des connaissances en programmation, que choisissez-vous d'enseigner ...

Comment obtenir des données d'information en contournant le mécanisme anti-frawler d'Investing.com? Comment obtenir des données d'information en contournant le mécanisme anti-frawler d'Investing.com? Apr 02, 2025 am 07:03 AM

Comprendre la stratégie anti-rampe d'investissement.com, Beaucoup de gens essaient souvent de ramper les données d'actualités sur Investing.com (https://cn.investing.com/news/latest-news) ...

See all articles