Frage

Was passiert, wenn zwei Module sie importieren?

Um das Problem zu verallgemeinern, was über die zyklischen Einfuhren in Python?

War es hilfreich?

Lösung

Es war eine wirklich gute Diskussion zu diesem über comp. lang.python im letzten Jahr. Es beantwortet Ihre Frage ziemlich gründlich.

  

Die Importe sind wirklich ziemlich einfach. Denken Sie daran, wie folgt vor:

     

'Import' und 'von xxx Import yyy' ausführbare Anweisungen sind. sie führen   wenn das laufende Programm erreicht diese Zeile.

     

Wenn ein Modul nicht in sys.modules ist, dann erzeugt ein Import das neue Modul   Eintrag in sys.modules und führt dann den Code in dem Modul. Es tut nicht   Rück Steuerung an das anrufende Modul, bis die Ausführung abgeschlossen hat.

     

Wenn ein Modul in sys.modules existiert dann ein Import einfach zurückgibt, dass   Modul, ob es die Ausführung abgeschlossen ist. Das ist der Grund, warum   zyklische Importe Module zurückkehren können, die teilweise leer erscheinen.

     

Schließlich läuft das Ausführen von Skripts in einem Modul namens __main__, Importieren   das Skript unter eigenem Namen ein neues Modul in keinem Zusammenhang erstellen   __main __.

     

Nehmen Sie die Menge zusammen und sollten Sie keine Überraschungen, beim Import   Module.

Andere Tipps

Wenn Sie in import foo und bar innen import bar foo tun, wird es gut funktionieren. Durch die Zeit, alles tatsächlich läuft, werden beide Module geladen wurde und Verweise miteinander haben werden.

Das Problem ist, wenn Sie stattdessen from foo import abc und from bar import xyz tun. Da nun jedes Modul erfordert das andere Modul bereits importiert werden (so dass der Name, den wir importieren vorhanden), bevor es importiert werden kann.

Zyklische Importe beenden, aber Sie müssen vorsichtig sein, nicht die konjunktur importierten Module während Modulinitialisierung zu verwenden.

Beachten Sie die folgenden Dateien:

a.py:

print "a in"
import sys
print "b imported: %s" % ("b" in sys.modules, )
import b
print "a out"

b.py:

print "b in"
import a
print "b out"
x = 3

Wenn Sie a.py ausführen, Sie erhalten die folgende:

$ python a.py
a in
b imported: False
b in
a in
b imported: True
a out
b out
a out

Auf dem zweiten Import von b.py (in der zweiten a in), das Python-Interpreter nicht importiert b wieder, weil es bereits im Modul dict vorhanden ist.

Wenn Sie versuchen, b.x zuzugreifen a während Modulinitialisierung, erhalten Sie eine AttributeError erhalten.

Fügen Sie die folgende Zeile in a.py:

print b.x

Dann wird die Ausgabe lautet:

$ python a.py
a in                    
b imported: False
b in
a in
b imported: True
a out
Traceback (most recent call last):
  File "a.py", line 4, in <module>
    import b
  File "/home/shlomme/tmp/x/b.py", line 2, in <module>
    import a
 File "/home/shlomme/tmp/x/a.py", line 7, in <module>
    print b.x
AttributeError: 'module' object has no attribute 'x'

Das ist, weil Module auf Import und zu der Zeit ausgeführt wird b.x zugegriffen wird, hat die Linie x = 3 noch nicht ausgeführt werden, die erst nach b out passieren werden.

Wie andere Antworten beschreiben dieses Muster in Python akzeptabel ist:

def dostuff(self):
     from foo import bar
     ...

, die die Ausführung der Import-Anweisung vermeiden, wenn die Datei von anderen Modulen importiert wird. Nur wenn es eine logische zirkuläre Abhängigkeit ist, wird dies nicht gelingen.

Die meisten Rund Importe sind nicht wirklich logisch Kreis Importe sondern ImportError Fehler erhöhen, wegen der Art und Weise import() Top-Level-Aussagen der gesamten Datei auswertet, wenn sie aufgerufen.

Diese können ImportErrors fast immer vermieden werden, wenn Sie positiv Ihre Importe oben wollen :

Betrachten Sie diesen Kreis Import:

App A

# profiles/serializers.py

from images.serializers import SimplifiedImageSerializer

class SimplifiedProfileSerializer(serializers.Serializer):
    name = serializers.CharField()

class ProfileSerializer(SimplifiedProfileSerializer):
    recent_images = SimplifiedImageSerializer(many=True)

App B

# images/serializers.py

from profiles.serializers import SimplifiedProfileSerializer

class SimplifiedImageSerializer(serializers.Serializer):
    title = serializers.CharField()

class ImageSerializer(SimplifiedImageSerializer):
    profile = SimplifiedProfileSerializer()

Von David Beazleys ausgezeichneten Talk Module und Packages: Leben und sterben lassen! - PyCon 2015 , 1:54:00, hier ist ein Weg, um mit Kreis Einfuhren in Python zu tun:

try:
    from images.serializers import SimplifiedImageSerializer
except ImportError:
    import sys
    SimplifiedImageSerializer = sys.modules[__package__ + '.SimplifiedImageSerializer']

Dies versucht SimplifiedImageSerializer zu importieren und wenn ImportError angehoben wird, weil es bereits importiert wird, wird es von der importcache ziehen.

PS:. Sie haben die gesamte Post in David Beazley Stimme lesen

Ich habe hier ein Beispiel, das mir geschlagen!

foo.py

import bar

class gX(object):
    g = 10

bar.py

from foo import gX

o = gX()

main.py

import foo
import bar

print "all done"

in der Befehlszeile: $ python main.py

Traceback (most recent call last):
  File "m.py", line 1, in <module>
    import foo
  File "/home/xolve/foo.py", line 1, in <module>
    import bar
  File "/home/xolve/bar.py", line 1, in <module>
    from foo import gX
ImportError: cannot import name gX

ich mit-Python-Antwort vollständig zustimmen hier. Aber ich habe auf einige Code gestolpert, die mit Kreis Importen und verursacht Probleme fehlerhaft war bei dem Versuch, Unit-Tests hinzuzufügen. So schnell es patchen, ohne alles ändern Sie das Problem beheben können einen dynamischen Import von tun.

# Hack to import something without circular import issue
def load_module(name):
    """Load module using imp.find_module"""
    names = name.split(".")
    path = None
    for name in names:
        f, path, info = imp.find_module(name, path)
        path = [path]
    return imp.load_module(name, f, path[0], info)
constants = load_module("app.constants")

Auch dies ist keine dauerhafte Lösung aber kann jemanden helfen, die ohne Änderung zu viel des Codes einen Importfehler beheben will.

Prost!

Modul a.py:

import b
print("This is from module a")

Modul b.py

import a
print("This is from module b")

Ausführen "Modul A" folgende Ausgabe:

>>> 
'This is from module a'
'This is from module b'
'This is from module a'
>>> 

Es Ausgang dieser 3 Zeilen, während es wegen Kreis Import zur Ausgabe infinitival soll. Was passiert, Zeile für Zeile während des Laufens „Modul A“ aufgeführt ist hier:

  1. Die erste Zeile ist import b. so wird es Modul b besuchen
  2. Die erste Zeile im Modul b import a. so wird es besuchen, um ein
  3. Modul
  4. Die erste Zeile im Modul a import b aber beachten Sie, dass diese Zeile nicht wieder mehr ausgeführt werden , da jede Datei in Python eine Import Linie nur einmal ausführen , ist es egal, wo oder wann sie ausgeführt wird. so wird es in der nächsten Zeile und Druck "This is from module a" passieren.
  5. Nach dem Finish gesamten Modul eines von Modul b besucht, sind wir noch am Modul b. so dass die nächste Zeile druckt "This is from module b"
  6. Modul b Zeilen werden vollständig ausgeführt. so werden wir wieder ein Modul, wo wir Modul b gestartet.
  7. Import b Linie bereits ausgeführt hat und nicht erneut ausgeführt werden. die nächste Zeile "This is from module a" gedruckt wird und das Programm wird beendet.

Rund Importe kann verwirrend sein, weil Import macht zwei Dinge:

  1. führt sie importierte Modul-Code
  2. fügt importierte Modul zu Modul globale Symboltabelle importieren

Der Erstere wird nur einmal durchgeführt, während diese bei jeder Import-Anweisung. Circular Import schafft Situation beim Import-Modul eines mit teilweise ausgeführten Code importiert verwendet. In der Folge sehen wird es keine Objekte nach dem Import-Anweisung erstellt. Im Folgenden Codebeispiel zeigt es.

Rund Importe sind nicht die ultimative böse auf jeden Fall vermieden werden. In einigen Frameworks wie Flask sind sie ganz natürlich und Ihren Code Tweaking zu eliminieren sie nicht der Code besser macht.

main.py

print 'import b'
import b
print 'a in globals() {}'.format('a' in globals())
print 'import a'
import a
print 'a in globals() {}'.format('a' in globals())
if __name__ == '__main__':
    print 'imports done'
    print 'b has y {}, a is b.a {}'.format(hasattr(b, 'y'), a is b.a)

b.by

print "b in, __name__ = {}".format(__name__)
x = 3
print 'b imports a'
import a
y = 5
print "b out"

a.py

print 'a in, __name__ = {}'.format(__name__)
print 'a imports b'
import b
print 'b has x {}'.format(hasattr(b, 'x'))
print 'b has y {}'.format(hasattr(b, 'y'))
print "a out"

Python main.py Ausgang mit Kommentaren

import b
b in, __name__ = b    # b code execution started
b imports a
a in, __name__ = a    # a code execution started
a imports b           # b code execution is already in progress
b has x True
b has y False         # b defines y after a import,
a out
b out
a in globals() False  # import only adds a to main global symbol table 
import a
a in globals() True
imports done
b has y True, a is b.a True # all b objects are available

Ich löste das Problem auf folgende Weise, und es funktioniert gut ohne Fehler. Betrachten wir zwei Dateien a.py und b.py.

Ich habe diese a.py und es funktionierte.

if __name__ == "__main__":
        main ()

a.py:

import b
y = 2
def main():
    print ("a out")
    print (b.x)

if __name__ == "__main__":
    main ()

b.py:

import a
print ("b out")
x = 3 + a.y

Der Ausgang ich erhalte, ist

>>> b out 
>>> a out 
>>> 5

Es gibt viele gute Antworten hier. Zwar gibt es in der Regel schnelle Lösungen für das Problem sind, von denen einige das Gefühl, mehr pythonic als andere, wenn Sie den Luxus zu tun, einige Umgestaltung haben, ein anderer Ansatz, um die Organisation des Codes zu analysieren und versuchen, die zirkuläre Abhängigkeit zu entfernen. Sie können zum Beispiel finden, dass Sie haben:

Datei a.py

from b import B

class A:
    @staticmethod
    def save_result(result):
        print('save the result')

    @staticmethod
    def do_something_a_ish(param):
        A.save_result(A.use_param_like_a_would(param))

    @staticmethod
    def do_something_related_to_b(param):
        B.do_something_b_ish(param)

Datei b.py

from a import A

class B:
    @staticmethod
    def do_something_b_ish(param):
        A.save_result(B.use_param_like_b_would(param))

In diesem Fall nur eine statische Methode in einer separaten Datei zu bewegen, sagen c.py:

Datei c.py

def save_result(result):
    print('save the result')

die save_result Methode von einem Entfernen ermöglichen, und ermöglicht es somit, die Einfuhr von A aus einer Entfernung von in b:

Überarbeitete Datei a.py

from b import B
from c import save_result

class A:
    @staticmethod
    def do_something_a_ish(param):
        A.save_result(A.use_param_like_a_would(param))

    @staticmethod
    def do_something_related_to_b(param):
        B.do_something_b_ish(param)

Überarbeitete Datei b.py

from c import save_result

class B:
    @staticmethod
    def do_something_b_ish(param):
        save_result(B.use_param_like_b_would(param))

Zusammenfassend: Wenn Sie ein Werkzeug (z Pylint oder PyCharm), die auf Methoden berichtet, die statisch sein kann, nur einen staticmethod Dekorateur auf sie werfen vielleicht nicht der beste Weg, um die Warnung zu unterdrücken. Obwohl die Methode der Klasse verwandt zu sein scheint, könnte es besser sein, es zu trennen, vor allem, wenn Sie mehrere eng verwandte Module, die die gleiche Funktionalität benötigen und Sie beabsichtigen, DRY Prinzipien zu üben.

Dies könnte eine andere Lösung sein, für mich gearbeitet.

def MandrillEmailOrderSerializer():
from sastaticketpk.apps.flights.api.v1.serializers import MandrillEmailOrderSerializer
return MandrillEmailOrderSerializer

email_data = MandrillEmailOrderSerializer()(order.booking).data

Ok, ich glaube, ich habe eine ziemlich coole Lösung. Angenommen, Sie Datei a und Datei b haben. Sie haben eine def oder eine class in Datei b, die Sie im Modul a verwenden möchten, aber Sie haben etwas anderes, entweder eine def, class oder Variable aus Datei a, die Sie in Ihrer Definition oder Klasse in der Datei b benötigen. Was können Sie tun, ist, am unteren Rand der Datei a, nachdem die Funktion oder Klasse in der Datei a aufrufen, die in der Datei b benötigt wird, aber bevor die Funktion oder Klasse aus Datei b aufrufen, die Sie für die Datei a benötigen, sagen import b Dann, und hier ist die Schlüsselteil , in alle Definitionen oder Klassen in der Datei b, die die def oder class von Datei a benötigen (nennen wir es CLASS), sagen Sie from a import CLASS

Das funktioniert, weil Sie Datei b ohne Python ausführen eine der Import-Anweisungen in der Datei b importieren können und somit entziehen Sie Kreis Importe.

Zum Beispiel:

Datei ein:

class A(object):

     def __init__(self, name):

         self.name = name

CLASS = A("me")

import b

go = B(6)

go.dostuff

Datei b:

class B(object):

     def __init__(self, number):

         self.number = number

     def dostuff(self):

         from a import CLASS

         print "Hello " + CLASS.name + ", " + str(number) + " is an interesting number."

Voila.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top