__init__ vs __enter__ in Kontextmanagern

9

Soweit ich weiß, werden die Methoden __init__() und __enter__() des Kontextmanagers nacheinander genau einmal aufgerufen, so dass kein anderer Code dazwischen ausgeführt werden kann. Was ist der Zweck, sie in zwei Methoden zu trennen, und was sollte ich in jeden einfügen?

Bearbeiten: Entschuldigung, habe die Dokumente nicht beachtet.

Edit 2: Der Grund, warum ich verwirrt wurde, ist, weil ich an @contextmanager Decorator dachte. Ein mit @contextmananger erstellter Kontextmanager kann nur einmal verwendet werden (der Generator ist nach der ersten Verwendung erschöpft), so oft werden sie mit dem Aufruf des Konstruktors in with statement geschrieben; und wenn das die einzige Möglichkeit wäre, with statement zu verwenden, hätte meine Frage Sinn ergeben. In der Realität sind Kontextmanager jedoch allgemeiner als das, was @contextmanager erzeugen kann; Insbesondere können Kontextmanager im Allgemeinen wiederverwendet werden. Ich hoffe, ich habe es diesmal richtig gemacht?

    
max 21.09.2016, 08:40
quelle

2 Antworten

22
  

Soweit ich weiß, werden die Methoden __init__() und __enter__() des Kontextmanagers nacheinander genau einmal aufgerufen, so dass dazwischen kein anderer Code ausgeführt werden kann.

Und dein Verständnis ist falsch. __init__ wird aufgerufen, wenn das Objekt erstellt wird, __enter__ , wenn es mit der with -Anweisung eingegeben wird, und dies sind zwei ziemlich unterschiedliche Dinge. Oft ist es so, dass der Konstruktor direkt in with initialization ohne intervenierenden Code aufgerufen wird, aber das muss nicht der Fall sein.

Betrachten Sie dieses Beispiel:

%Vor%

myobj kann separat initialisiert und in mehrere with Blöcke eingegeben werden:

Ausgabe:

%Vor%

Darüber hinaus, wenn __init__ und __enter__ nicht getrennt wurden, wäre es nicht möglich, Folgendes zu verwenden:

%Vor%

seit der Initialisierung (in open ) ist klar getrennt von with entry.

Die Manager, die von contextlib.manager erstellt wurden, sind Einzelspieler, aber sie sind es wieder kann außerhalb des with -Blocks erstellt werden. Nehmen Sie das Beispiel:

%Vor%

Sie können dies als:

verwenden %Vor%

Ausgabe:

%Vor%

Wenn Sie jedoch versuchen, my_heading (und folglich tag ) wiederzuverwenden, erhalten Sie

%Vor%     
Antti Haapala 21.09.2016, 08:44
quelle
0

Antti Haapalas Antwort ist völlig in Ordnung. Ich wollte nur ein wenig auf die Verwendung von Argumenten eingehen (wie myClass(* args) ), da das für mich etwas unklar war (Rückblick, ich frage mich, warum ....)

Das Verwenden von Argumenten zum Initialisieren Ihrer Klasse in einer with -Anweisung unterscheidet sich nicht von der normalen Verwendung der Klasse. Die Anrufe werden in der folgenden Reihenfolge ausgeführt:

  1. __init__ (Zuweisung der Klasse)
  2. __enter__ (Kontext eingeben)
  3. __exit__ (Kontext verlassen)

Einfaches Beispiel:

%Vor%

Ausgabe:

%Vor%

Wenn Sie sicherstellen möchten, dass Ihre Aufrufe (fast) nur in einem Kontext verwendet werden können (z. B. um den Aufruf von __exit__ zu erzwingen), lesen Sie den Artikel stackoverflow post hier . In den Kommentaren finden Sie auch dann eine Antwort auf die Frage, wie man Argumente verwendet.

    
SeparateReality 26.11.2017 13:36
quelle