Nehmen wir an, ich habe die folgende Verzeichnisstruktur:
a
__init__.py
b
__init__.py
c
__init__.py
c_file.py
d
__init__.py
d_file.py
Im a Pakete __init__.pydas c Paket wird importiert. Aber c_file.py Importe a.b.d.
Das Programm schlägt fehl, sagen b existiert nicht wann c_file.py versucht zu importieren a.b.d. (Und es existiert wirklich nicht, weil wir gerade dabei waren, es zu importieren.)
Wie kann dieses Problem behoben werden?
Vielleicht könntest du es mit relativen Importen versuchen? stackoverflow.com/questions/72852/…
Auch nur als Referenz, es scheint, dass zirkuläre Importe auf Python 3.5 (und wahrscheinlich darüber hinaus) erlaubt sind, aber nicht auf 3.4 (und wahrscheinlich unten).
– Charly Parker
8. Februar 17 um 15:18 Uhr
Wenn Sie den Importfehler abfangen, funktioniert es einwandfrei, solange Sie nichts im anderen Modul verwenden müssen, bevor das erste Modul den Import abgeschlossen hat.
– Gavin S. Yancey
9. Juni 17 um 19:38 Uhr
Mögliches Duplikat von kreisförmigen (oder zyklischen) Importen in Python
– Ciro Santilli 新疆再教育营六四事件法轮功郝海东
8. März 19 um 15:49 Uhr
Sie können den Import verschieben, zum Beispiel in a/__init__.py:
def my_function():
from a.b.c import Blah
return Blah()
das heißt, verschieben Sie den Import, bis er wirklich benötigt wird. Allerdings würde ich mir auch meine Paketdefinitionen/-verwendungen genau ansehen, da eine zyklische Abhängigkeit wie die erwähnte auf ein Designproblem hindeuten könnte.
Manchmal sind Zirkelbezüge wirklich unvermeidlich. Dies ist der einzige Ansatz, der für mich unter diesen Umständen funktioniert.
– Jason Polites
12. März 13 um 21:29 Uhr
Würde dies nicht bei jedem Aufruf von foo eine Menge Overhead hinzufügen?
– Herr_und_Frau_D
17. September 14 um 23:15 Uhr
@Mr_and_Mrs_D – nur mäßig. Python speichert alle importierten Module in einem globalen Cache (sys.modules), so dass ein einmal geladenes Modul nicht erneut geladen wird. Der Code könnte eine Namenssuche bei jedem Anruf beinhalten my_functionaber auch Code, der Symbole über qualifizierte Namen referenziert (z. B. import foo; foo.frobnicate())
– Dirk
18. September 14 um 7:55 Uhr
Von allen möglichen Lösungen hier ist dies die einzige, die für mich funktioniert hat. Es gibt durchaus Umstände, unter denen ein Zirkelverweis die „beste“ Lösung ist – insbesondere, wenn Sie eine Reihe von Modellobjekten auf mehrere Dateien aufteilen, um die Dateigröße einzuschränken.
–Richard J
24. September 14 um 12:06 Uhr
Manchmal sind Zirkelbezüge genau der richtige Weg, um das Problem zu modellieren. Die Vorstellung, dass zirkuläre Abhängigkeiten irgendwie ein Hinweis auf schlechtes Design sind, scheint eher eine Reflexion über Python als Sprache zu sein als ein legitimer Designpunkt.
– Julie in Austin
25. Mai ’15 um 6:34 Uhr
Wenn a von c abhängt und c von a abhängt, sind sie dann nicht tatsächlich dieselbe Einheit?
Sie sollten wirklich prüfen, warum Sie a und c in zwei Pakete aufgeteilt haben, denn entweder haben Sie Code, den Sie in ein anderes Paket aufteilen sollten (um beide von diesem neuen Paket abhängig zu machen, aber nicht voneinander), oder Sie sollten sie zusammenführen in einem Paket.
Ja, sie könnten als dasselbe Paket betrachtet werden. Wenn dies jedoch zu einer sehr großen Datei führt, ist dies unpraktisch. Ich stimme zu, dass häufig zirkuläre Abhängigkeiten bedeuten, dass das Design noch einmal überdacht werden sollte. Aber es GIBT einige Designmuster, wo es angebracht ist (und wo das Zusammenführen der Dateien zu einer riesigen Datei führen würde), daher denke ich, dass es dogmatisch ist zu sagen, dass die Pakete entweder kombiniert oder das Design neu bewertet werden sollte.
– Matthäus Lund
1. Dezember 11 um 21:49 Uhr
zachaysan
Ich habe mich das ein paar Mal gefragt (normalerweise, wenn ich mit Models zu tun habe, die voneinander wissen müssen). Die einfache Lösung besteht darin, einfach das gesamte Modul zu importieren und dann auf das zu verweisen, was Sie benötigen.
Also anstatt zu tun
from models import Student
in einem und
from models import Classroom
im anderen tun Sie es einfach
import models
in einem von ihnen, dann anrufen models.Classroom wenn du es brauchst.
Können Sie zeigen, wie models.py aussieht? Ich möchte nicht alle Klassendefinitionen in einer Datei ablegen. Ich möchte eine models.py erstellen, die jede Klasse aus ihrer eigenen Datei importiert. Ich muss eine Beispieldateistruktur sehen.
– ROMS
16. August 21 um 18:01 Uhr
Es muss nicht eine Datei sein, @ROMS-Modelle kann ein Verzeichnis sein, das eine enthält __init__.py Datei, aus der importiert wird models.classroom.
– zachaysan
17. August 21 um 12:52 Uhr
Christoph Peisert
Zirkuläre Abhängigkeiten aufgrund von Typhinweisen
Mit Typhinweisen gibt es mehr Möglichkeiten zum Erstellen von zirkulären Importen. Glücklicherweise gibt es eine Lösung mit der speziellen Konstante: typing.TYPE_CHECKING.
Das folgende Beispiel definiert a Vertex Klasse und ein Edge Klasse. Eine Kante wird durch zwei Scheitelpunkte definiert, und ein Scheitelpunkt verwaltet eine Liste der angrenzenden Kanten, zu denen er gehört.
ImportError: Name „Edge“ kann nicht aus teilweise initialisiertem Modul „Edge“ importiert werden (höchstwahrscheinlich aufgrund eines zirkulären Imports)
Datei: vertex.py
from typing import List
from edge import Edge
class Vertex:
def __init__(self, label: str):
self.label = label
self.adjacency_list: List[Edge] = []
Datei: edge.py
from vertex import Vertex
class Edge:
def __init__(self, v1: Vertex, v2: Vertex):
self.v1 = v1
self.v2 = v2
Lösung mit TYPE_CHECKING
Datei: vertex.py
from typing import List, TYPE_CHECKING
if TYPE_CHECKING:
from edge import Edge
class Vertex:
def __init__(self, label: str):
self.label = label
self.adjacency_list: List['Edge'] = []
Datei: edge.py
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from vertex import Vertex
class Edge:
def __init__(self, v1: 'Vertex', v2: 'Vertex'):
self.v1 = v1
self.v2 = v2
In Anführungszeichen gesetzte vs. Nicht in Anführungszeichen gesetzte Typhinweise
In Python-Versionen vor 3.10 müssen bedingt importierte Typen in Anführungszeichen gesetzt werden, wodurch sie zu „Weiterleitungsverweisen“ werden, wodurch sie vor der Laufzeit des Interpreters verborgen werden.
In Python 3.7, 3.8 und 3.9 besteht eine Problemumgehung darin, den folgenden speziellen Import zu verwenden.
from __future__ import annotations
Dies ermöglicht die Verwendung von Typhinweisen ohne Anführungszeichen in Kombination mit bedingten Importen.
In Python 3.10 werden Funktions- und Variablenannotationen nicht mehr zur Definitionszeit ausgewertet. Stattdessen wird eine Zeichenfolgenform im jeweiligen beibehalten Anmerkungen Wörterbuch. Statische Typprüfer sehen keinen Unterschied im Verhalten, während Tools, die Annotationen zur Laufzeit verwenden, eine verzögerte Auswertung durchführen müssen.
Die Zeichenfolgenform wird während des Kompilierungsschritts vom AST abgerufen, was bedeutet, dass die Zeichenfolgenform möglicherweise nicht die genaue Formatierung der Quelle beibehält. Hinweis: Wenn eine Anmerkung bereits ein Zeichenfolgenliteral war, wird sie dennoch in eine Zeichenfolge eingeschlossen.
Das Problem ist, dass beim Ausführen aus einem Verzeichnis standardmäßig nur die Pakete, die Unterverzeichnisse sind, als mögliche Importe sichtbar sind, sodass Sie nicht abd importieren können. Sie können jedoch bd importieren, da b ein Unterpaket von a ist.
Wenn Sie wirklich abd in importieren möchten c/__init__.py Sie können dies erreichen, indem Sie den Systempfad auf ein Verzeichnis über a ändern und den Import in ändern a/__init__.py Import abc sein
Deine a/__init__.py sollte so aussehen:
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
Eine zusätzliche Schwierigkeit ergibt sich, wenn Sie Module in c als Skripte ausführen wollen. Hier existieren die Pakete a und b nicht. Sie können die hacken __int__.py im Verzeichnis c, um den sys.path auf das Verzeichnis der obersten Ebene zu verweisen, und importieren Sie dann __init__ in allen Modulen innerhalb von c, um den vollständigen Pfad zum Importieren verwenden zu können, bezweifle ich, dass es sich bewährt hat, zu importieren __init__.py aber es hat für meine Anwendungsfälle funktioniert.
RaamEE
Ich schlage folgendes Muster vor. Wenn Sie es verwenden, können die automatische Vervollständigung und die Typhinweise ordnungsgemäß funktionieren.
zyklischer_import_a.py
import playground.cyclic_import_b
class A(object):
def __init__(self):
pass
def print_a(self):
print('a')
if __name__ == '__main__':
a = A()
a.print_a()
b = playground.cyclic_import_b.B(a)
b.print_b()
zyklischer_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-----------------')
Sie können die Klassen A und B nicht mit dieser Syntax importieren
from playgroud.cyclic_import_a import A
from playground.cyclic_import_b import B
Sie können den Typ des Parameters a nicht in der Methode Klasse B __ init __ deklarieren, aber Sie können ihn auf diese Weise “umwandeln”:
def __init__(self, a):
self.a: playground.cyclic_import_a.A = a
Eine andere Lösung besteht darin, einen Proxy für die d_file zu verwenden.
Nehmen wir zum Beispiel an, Sie möchten die blah-Klasse mit der c_file teilen. Die d_file enthält also:
class blah:
def __init__(self):
print("blah")
Folgendes geben Sie in c_file.py ein:
# 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()
Und in einem drin.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()
Das Ändern globaler Modulattribute in einer anderen Datei wie dieser führt schnell zu einem Alptraum
– Antimon
29. Juli 12 um 2:49 Uhr
.
8225500cookie-checkZirkuläre Importabhängigkeit in Pythonyes
Vielleicht könntest du es mit relativen Importen versuchen? stackoverflow.com/questions/72852/…
– Eremzeit
2. September 11 um 0:30 Uhr
das kann helfen ncoghlan_devs-python-notes.readthedocs.org/en/latest/…
– mazza
3. Januar 14 um 10:12 Uhr
Auch nur als Referenz, es scheint, dass zirkuläre Importe auf Python 3.5 (und wahrscheinlich darüber hinaus) erlaubt sind, aber nicht auf 3.4 (und wahrscheinlich unten).
– Charly Parker
8. Februar 17 um 15:18 Uhr
Wenn Sie den Importfehler abfangen, funktioniert es einwandfrei, solange Sie nichts im anderen Modul verwenden müssen, bevor das erste Modul den Import abgeschlossen hat.
– Gavin S. Yancey
9. Juni 17 um 19:38 Uhr
Mögliches Duplikat von kreisförmigen (oder zyklischen) Importen in Python
– Ciro Santilli 新疆再教育营六四事件法轮功郝海东
8. März 19 um 15:49 Uhr