Wie überprüft man, ob ein Objekt mit 'mit' Anweisung erstellt wird?

7

Ich möchte sicherstellen, dass die Klasse nur innerhalb einer "with" -Anweisung instanziiert wird.

d. dieser ist in Ordnung:

%Vor%

und das ist nicht:

%Vor%

Wie kann ich diese Funktionalität sicherstellen?

    
vpas 14.02.2015, 15:41
quelle

5 Antworten

2

Alle bisherigen Antworten liefern nicht, was (ich glaube) OP direkt wollen .
(Ich denke) OP möchte so etwas:

%Vor%

Das ist, was ich vorhabe, es mag nicht sehr robust sein, aber ich denke, es liegt am nächsten bei OPs Absicht.

%Vor%

Dies gibt genau die gleiche Ausgabe wie oben gezeigt, solange with in derselben Zeile mit X() liegt, wenn der Kontextmanager verwendet wird.

    
laike9m 14.02.2015, 17:13
quelle
9

Es gibt keinen direkten Weg, soweit ich weiß. Sie können jedoch ein boolesches Flag verwenden, um zu überprüfen, ob __enter__ aufgerufen wurde, bevor die tatsächlichen Methoden in den Objekten aufgerufen wurden.

%Vor%

Wenn Sie es mit with verwenden,

%Vor%

Sie werden

erhalten %Vor%

Wenn Sie jedoch ein Objekt manuell erstellen und do_something aufrufen,

%Vor%

Sie werden

erhalten %Vor%

Hinweis: Dies ist keine feste Lösung. Jemand kann direkt __enter__ -Methode aufrufen, bevor andere Methoden aufgerufen werden, und die Methode __exit__ wird in diesem Fall niemals aufgerufen.

Wenn Sie diese Überprüfung nicht in jeder Funktion wiederholen möchten, können Sie sie zu einem Dekorateur machen, wie dies hier beschrieben wird.

%Vor%     
thefourtheye 14.02.2015 16:04
quelle
7

Es gibt keine narrensichere Methode, um sicherzustellen, dass eine Instanz in einer with -Klausel erstellt wird. Sie können jedoch eine Instanz in der Methode __enter__ erstellen und diese anstelle von self ; Dies ist der Wert, der in x zugewiesen wird. Daher können Sie X als Factory betrachten, die die tatsächliche Instanz in ihrer __enter__ -Methode erstellt, etwa wie folgt:

%Vor%

Natürlich ist dies immer noch wiederverwendbar, aber jede with Anweisung würde eine neue Instanz erstellen.

Natürlich kann man __enter__ manuell aufrufen oder einen Verweis auf das ActualInstanceClass erhalten, aber es wäre mehr missbrauchen anstatt zu verwenden.

Für einen noch geruchsärmeren Ansatz erzeugt das X() beim Aufruf tatsächlich eine XFactory -Instanz anstelle einer X -Instanz; und diese wiederum erstellt, wenn sie als Kontextmanager verwendet wird, die ActualX -Instanz, die die Unterklasse von X ist, daher wird isinstance(x, X) den Wert true zurückgeben.

%Vor%

Du könntest das weiterführen und XFactory eine tatsächliche X -Instanz mit einem speziellen Schlüsselwort-Argument für __new__ erstellen lassen, aber ich halte es für zu schwarz, um nützlich zu sein.

    
Antti Haapala 14.02.2015 16:19
quelle
3

Leider können Sie nicht sehr sauber.

Kontextmanager benötigen die Methoden __enter__ und __exit__ , damit Sie eine Membervariable für die Klasse zum Einchecken Ihres Codes zuweisen können.

%Vor%

Der statusbehaftete Objektansatz hat den zusätzlichen Vorteil, dass er später feststellen kann, ob die __exit__ -Methode aufgerufen wurde, oder um Methodenanforderungen in späteren Aufrufen sauber zu behandeln:

%Vor%     
user559633 14.02.2015 16:28
quelle
1

Hier ist ein Decorator, der automatisiert, dass Methoden nicht außerhalb eines Kontextmanagers aufgerufen werden:

%Vor%

Und hier ist ein Beispiel dafür:

%Vor%

Dies wurde als Antwort auf diese doppelte Frage .

    
agf 05.06.2015 19:42
quelle

Tags und Links