Python-Zirkularimport
- Zirkulärer Importfehler in Python reproduzieren
- Beheben Sie den zirkulären Importfehler in Python
- Beheben Sie den zirkulären Importfehler, der durch den Typhinweis in Python verursacht wurde
In diesem Artikel erfahren Sie, wie zirkuläre Importe häufig entstehen und wie Sie sie beheben können. Wir werden auch sehen, wie ein zirkulärer Importfehler behoben wird, der durch einen Typhinweis in Python verursacht wird.
Zirkulärer Importfehler in Python reproduzieren
Sind Sie beim Versuch, ein Modul zu importieren, schon einmal auf einen Fehler gestoßen? In diesem Fall erhalten wir einen Fehler, der unten gezeigt wird.
from My_Module_A import My_FUNC_A
def My_main_Func():
My_FUNC_A()
if __name__ == "main":
My_main_Func()
Ausgang:
ImportError: cannot import name 'My_FUNC_A' from partially initialized module 'My_Module_A' (most likely due to a circular import)
Es sagt uns, dass die wahrscheinlichste Ursache ein zirkulärer Import ist. Hier ist der einfachste und gebräuchlichste Weg, wie diese Art von Importzyklus zur Laufzeit passieren kann. main hat versucht, etwas aus My_Module_A
zu importieren.
Es beginnt also mit der Initialisierung von My_Module_A
und der Ausführung des Codes von My_Module_A
, aber die erste Zeile in My_Module_A
besteht darin, etwas aus dem Modul MY_Module_B
zu importieren.
Es stoppt also die Initialisierung des Moduls My_Module_A
, da MY_Module_B
zuerst initialisiert werden muss. Und dann springt es zu MY_Module_B
und beginnt stattdessen mit der Ausführung dieses Codes.
Aber die erste Zeile im Modul MY_Module_B
wird etwas von My_Module_A
benötigt, also stoppt es die Ausführung von MY_Module_B
und geht zu My_Module_A
über.
Und es möchte mit der Initialisierung von My_Module_A
beginnen, stellt aber fest, dass sich My_Module_A
bereits im Initialisierungsprozess befindet. Da tritt also der Fehler auf.
Wir können sehen, wie sich diese Kette von Ereignissen im Traceback entfaltet. Hier sehen wir in main.py
; Es versucht, die Funktion My_FUNC_A
aus dem Modul My_Module_A
zu importieren, was den Import der Funktion MY_Func_B2
aus dem Modul MY_Module_B
ausgelöst hat.
Und MY_Module_B.py
löste den Import der Funktion My_FUNC_A
erneut aus dem Modul My_Module_A
aus, wo der letzte Fehler auftrat.
Traceback (most recent call last):
File "c:\Users\Dell\Desktop\demo\main.py", line 1, in <module>
from My_Module_A import My_FUNC_A
File "c:\Users\Dell\Desktop\demo\My_Module_A.py", line 1, in <module>
from MY_Module_B, import MY_Func_B2
File "c:\Users\Dell\Desktop\demo\MY_Module_B.py", line 1, in <module>
from My_Module_A import My_FUNC_A
ImportError: cannot import name 'My_FUNC_A' from partially initialized module 'My_Module_A' (most likely due to a circular import) (c:\Users\Dell\Desktop\demo\My_Module_A.py)
Wir haben einen Importzeitzyklus zwischen den Modulen My_Module_A
und MY_Module_B
, aber wenn Sie sich die Namen ansehen, die wir importiert haben, verwenden wir sie nicht zur Importzeit.
Wir verwenden sie, wenn diese Funktion My_FUNC_A()
oder wenn diese Funktion MY_Func_B2()
aufgerufen wird. Da wir diese Funktionen nicht zur Importzeit aufrufen, gibt es keine echte zyklische Abhängigkeit, was bedeutet, dass wir diesen Importzyklus eliminieren können.
Beheben Sie den zirkulären Importfehler in Python
Es gibt drei gängige Möglichkeiten, dieses Problem zu lösen; Die erste besteht darin, Ihren Import zu nehmen und ihn in die Funktion einzufügen.
In Python können Importe jederzeit stattfinden, auch wenn eine Funktion aufgerufen wird; Wenn Sie diese Funktion MY_Func_B1()
benötigen, könnte dies der Import innerhalb der Funktion My_FUNC_A()
sein.
def My_FUNC_A():
from MY_Module_B import MY_Func_B1
MY_Func_B1()
Es könnte sogar noch effizienter sein, denn wenn Sie die Funktion My_FUNC_A()
nie aufrufen, dann müssen Sie möglicherweise MY_Func_B1
überhaupt nicht importieren. Nehmen wir zum Beispiel an, Sie haben eine Reihe verschiedener Funktionen in My_Module_A
, und viele verschiedene verwenden diese Funktion MY_Func_B1()
.
In diesem Fall wäre die bessere Lösung, das Modul MY_Module_B
direkt zu importieren und in den Funktionen, in denen Sie es verwenden, den längeren Namen wie MY_Module_B.MY_Func_B1()
zu verwenden. Machen Sie also weiter und führen Sie diese Konvertierung für alle am Zyklus beteiligten Module durch.
import MY_Module_B
def My_FUNC_A():
MY_Module_B.MY_Func_B1()
Mal sehen, wie dies den Importzyklus bei Laufzeitfehler behebt. Zuerst versucht unsere Funktion My_main_Func()
, etwas aus My_Module_A
zu importieren, wodurch My_Module_A
gestartet wird. Dann importieren wir in My_Module_A.py
das Modul MY_Module_B
, das den Start von MY_Module_B
auslöst.
Wenn wir in MY_Module_B.py
zum Importmodul My_Module_A
gelangen, hat das Modul bereits mit der Initialisierung begonnen; dieses Modulobjekt existiert technisch. Da es existiert, beginnt es nicht, dies erneut auszuführen.
Es sagt nur, okay, das existiert, also fährt das Modul MY_Module_B
fort, beendet seinen Import, und nachdem dieser Import abgeschlossen ist, beendet das Modul My_Module_A
den Import.
Ausgang:
15
Die dritte und letzte übliche Möglichkeit, diesen Importzyklus zu eliminieren, besteht darin, die beiden Module zusammenzuführen. Also wieder keine Importe, keine Importzyklen; Wenn Sie jedoch überhaupt zwei oder vielleicht sogar mehr Module hatten, hatten Sie sie wahrscheinlich aus einem bestimmten Grund.
Wir werden Ihnen nicht nur empfehlen, alle Ihre Module zu nehmen und sie zu einem zusammenzuführen; das wäre albern. Daher sollten Sie wahrscheinlich eine der ersten beiden Methoden bevorzugen.
Quellcode der Datei My_Module_A.py
.
import MY_Module_B
def My_FUNC_A():
print(MY_Module_B.MY_Func_B1())
Quellcode der Datei MY_Module_B.py
.
import My_Module_A
def MY_Func_B1():
return 5 + 10
def MY_Func_B2():
My_Module_A.My_FUNC_A()
Quellcode der Datei main.py
.
from My_Module_A import My_FUNC_A
def My_main_Func():
My_FUNC_A()
if __name__ == "main":
My_main_Func()
Beheben Sie den zirkulären Importfehler, der durch den Typhinweis in Python verursacht wurde
Schauen wir uns ein weiteres Beispiel an, die folgende häufigste Art von Importzyklus, die Sie aufgrund der Verwendung von Typhinweisen ausführen werden. Dieses Beispiel unterscheidet sich vom vorherigen, da Typanmerkungen für eine Funktions- oder Klassendefinition definiert werden.
Wenn die Funktion definiert ist oder die Klasse definiert, aber nicht definiert ist, wenn wir sie ausführen, ist der häufigste Anwendungsfall von Typhinweisen nicht einmal zur Laufzeit. Wenn uns nur die statische Analyse wichtig ist, brauchen wir nicht einmal den Import zur Laufzeit durchzuführen.
Das Modul typing
stellt diese Variable zur Verfügung, TYPE_CHECKING
ist zur Laufzeit eine falsche Konstante. Wenn wir also alle Importe, die wir für die Typprüfung benötigen, in eine davon stecken, wird zur Laufzeit nichts passieren.
Um die Importschleife ganz zu vermeiden, erhalten Sie beim Importieren dieser Klasse Mod_A_class
einen Namensfehler, da dieser Name Mod_A_class
nicht importiert wurde.
Ausgang:
Traceback (most recent call last):
File "c:\Users\Dell\Desktop\demo\main.py", line 1, in <module>
from My_Module_A import My_FUNC_A
File "c:\Users\Dell\Desktop\demo\My_Module_A.py", line 9, in <module>
from MY_Module_B, import MY_Func_B1
File "c:\Users\Dell\Desktop\demo\MY_Module_B.py", line 22, in <module>
class Mod_b_class:
File "c:\Users\Dell\Desktop\demo\MY_Module_B.py", line 23, in Mod_b_class
def __init__(self,a : Mod_A_class):
NameError: name 'Mod_A_class' is not defined
Um dies zu beheben, fügen Sie dies aus __future__
import annotations
hinzu. Was macht das?
Es ändert die Funktionsweise von Anmerkungen; Anstatt Mod_b_class
als Namen auszuwerten, werden alle Annotationen in Strings umgewandelt.
Hier bekommt man nun also zur Laufzeit keinen Fehler mehr, denn obwohl der Name Mod_b_class
nicht importiert wird, existiert der String Mod_b_class
durchaus. Sie sollten sich jedoch darüber im Klaren sein, dass, wenn Sie einen dieser Importe aus __future__
durchführen, dies nicht unbedingt für immer ein garantiertes Verhalten ist.
Dies führt nun dazu, dass Ihre Anmerkungen als Zeichenfolgen behandelt werden, aber es gibt einen konkurrierenden Vorschlag, sie nur träge auszuwerten. Daher werden sie nicht ausgewertet, es sei denn, Sie versuchen, sie anzusehen und Ihre Typhinweise zur Laufzeit zu überprüfen.
Dies wird wahrscheinlich keinen Unterschied für Ihre Codebasis machen, aber Sie sollten sich dessen bewusst sein. Eine alternative Lösung ist, statt from module imports
wieder module importieren
zu verwenden, und Sie benötigen weiterhin die annotations
von __future__
.
Vollständiger Quellcode des Moduls My_Module_A.py
.
# from __future__ import annotations
# from typing import TYPE_CHECKING
# from MY_Module_B import MY_Func_B1
# if TYPE_CHECKING:
# from MY_Module_B import Mod_b_class
# def My_FUNC_A():
# b : Mod_b_class = MY_Func_B1()
# class Mod_A_class:
# def __init__(self,b : Mod_b_class):
# self.b=b
from __future__ import annotations
import MY_Module_B
def My_FUNC_A():
b: MY_Module_B.Mod_b_class = MY_Module_B.MY_Func_B1()
class Mod_A_class:
def __init__(self, b: MY_Module_B.Mod_b_class):
self.b = b
Vollständiger Quellcode des Moduls MY_Module_B.py
.
from __future__ import annotations
import My_Module_A
def MY_Func_B1():
...
class Mod_b_class:
def __init__(self, a: My_Module_A.Mod_A_class):
self.a = a
Vollständiger Quellcode der Datei main.py
.
from My_Module_A import My_FUNC_A
def My_main_Func():
My_FUNC_A()
if __name__ == "main":
My_main_Func()
Hello! I am Salman Bin Mehmood(Baum), a software developer and I help organizations, address complex problems. My expertise lies within back-end, data science and machine learning. I am a lifelong learner, currently working on metaverse, and enrolled in a course building an AI application with python. I love solving problems and developing bug-free software for people. I write content related to python and hot Technologies.
LinkedInVerwandter Artikel - Python Import
- Importieren alle Funktionen aus einer Datei in Python
- Python Import aller Module in einem Verzeichnis
- Importieren einer Variable aus einer anderen Datei in Python
- Importieren eines Moduls aus einem vollständigen Dateipfad in Python
- Importieren von Modulen aus dem übergeordneten Verzeichnis in Python