2016-02-18 7 views
5
import contextlib 
import time 

@contextlib.contextmanager 
def time_print(task_name): 
    t = time.time() 
    try: 
     yield 
    finally: 
     print task_name, "took", time.time() - t, "seconds." 


def doproc(): 
    x=1+1 


with time_print("processes"): 
    [doproc() for _ in range(500)] 

# processes took 15.236166954 seconds. 

wann wird doproc ausgeführt, wenn dieser dekorator verwendet wird?was ergibt ohne Wert im kontext manager

+0

[Aus der Dokumentation:] (https://docs.python.org/2/library/contextlib.html#contextlib.contextmanager) "An dem Punkt, an dem der Generator nachgibt, wird der in der With-Anweisung geschachtelte Block ausgeführt. Der Generator wird dann wieder aufgenommen, nachdem der Block verlassen wurde. Wenn eine unbehandelte Ausnahme im Block auftritt, wird er innerhalb des Generators an diesem Punkt wieder aufgerufen wo der Ertrag aufgetreten ist. " –

+0

"Ausbeute" ohne Argument ist semantisch gleichbedeutend mit "Ausbeute keine" –

Antwort

7

yield Ausdruck gibt die Kontrolle an das zurück, was den Generator verwendet. Der Generator pausiert an dieser Stelle, was bedeutet, dass der @contextmanager Dekorateur weiß, dass der Code mit dem Setup Teil gemacht wird.

Mit anderen Worten, alles, was Sie im Kontextmanager __enter__ Phase tun möchten, muss vor der yield stattfinden.

Sobald Ihr Kontext verlässt (so der Block unter der with Anweisung erfolgt), der @contextmanager Dekorateur für die __exit__ Teil des Kontextes Manager-Protokoll genannt und wird eines von zwei Dingen tun:

  • Wenn Es gab keine Ausnahme, es wird Ihren Generator fortsetzen. Also Ihr Generator hebt die Pause an der yield Linie, und geben Sie die Bereinigungsphase, den Teil

  • Wenn es eine Ausnahme war, der Dekorateur verwendet generator.throw() diese Ausnahme im Generator zu erhöhen. Es wird sein, als ob die yield Zeile diese Ausnahme verursacht hat. Da Sie eine finally-Klausel haben, wird diese vor dem Beenden des Generators wegen der Ausnahme ausgeführt.

in Ihrem speziellen Beispiel So ist die Reihenfolge wie folgt:

  1. with time_print("processes"):

    Dies schafft den Kontext-Manager und fordert __enter__ darauf. Der Generator startet die Ausführung, t = time.time() wird ausgeführt.

  2. Der Ausdruck yield pausiert den Generator, die Steuerung geht zurück zum Dekorateur. Dies nimmt, was auch immer geliefert wurde und gibt das an die with Anweisung zurück, falls es einen as target Teil gibt.

  3. [doproc() for _ in range(500)] wird ausgeführt und abgeschlossen.

  4. Der Kontext-Manager __exit__ Methode ausgeführt wird, wird keine Ausnahme bestanden.

  5. Der Dekorateur nimmt den Generator, geht es weiter, wo sie aufgehört haben.

  6. Der finally: Block wird eingegeben und print task_name, "took", time.time() - t, "seconds." wird ausgeführt.

  7. Der Generator beendet, der Dekorateur __exit__ Methode beendet, alles ist fertig.

Verwandte Themen