Generator aufräumen auch wenn unbenutzt?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Tach!

Mit

Code: Alles auswählen

try:
  ... yield ...
finally:
  aufräum()
kann man ja Aufräumarbeiten machen, wenn der Generator zu Ende ist, garbage-collected wird oder eine Exception auftrat.

Wird der aus dem Funktionsaufruf resultierende Generator aber nie angefasst, wird der `finally`-Block natürlich nicht ausgeführt -- kennt jemand eine elegante Möglichkeiten, in diesem Fall Aufräumarbeiten zu erledigen?

Code: Alles auswählen

def somegen():
  try:
    ... yield ...
  finally:
    aufräum()

somegen() # Generator wird nicht "angestoßen"
Dankesehr :-)

Edit: was natürlich geht, ist, das Teil zu wrappen, was aber voraussetzt, dass ich die Aufräumarbeiten außerhalb der Generatorfunktion machen kann. Das würde ich gerne vermeiden.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Ich verstehe das Problem nicht. Dieses Beispiel zeigt "1", "2" und "Cleanup":

Code: Alles auswählen

def g():
    yield 1
    yield 2
    print "Cleanup"

for i in g():
    print i
Wenn man will, kann man auch try/finally benutzen:

Code: Alles auswählen

def g():
    try:
        yield 1
        raise Exception
    finally:
        print "Cleanup"

for i in g():
    print i
Stefan
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

sma hat geschrieben:Ich verstehe das Problem nicht. Dieses Beispiel zeigt "1", "2" und "Cleanup":

Code: Alles auswählen

def g():
    yield 1
    yield 2
    print "Cleanup"

for i in g():
    print i

Code: Alles auswählen

def g():
    yield 1
    yield 2
    print "Cleanup"

g()
zeigt aber kein "Cleanup". Ich suche eine Möglichkeit, auch dann Aufräumarbeiten durchzuführen, wenn der Generator niemals "betreten" wird.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Warum willst du etwas aufräumen, wenn du noch gar nichts getan hast? In deinem Beispiel wird doch überhaupt kein Code von g() durchlaufen. Dazu musst du erst einmal next() auf dem von g() zurückgelieferten Generator aufrufen. Und dann funktioniert auch wieder try/finally wie gewohnt.

Stefan
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

sma hat geschrieben:Warum willst du etwas aufräumen, wenn du noch gar nichts getan hast?
Extra für dich hol' ich ein wenig weiter aus. :-P

Der Generator iteriert über das Resultat einer Map/Reduce-Operation auf MongoDB, das in einer temporären Collection (das MongoDB-Äquivalent zu Tabellen, falls du dich damit nicht auskennst) gespeichert wird. Jetzt möchte ich ein Argument `drop_collection` anbieten, das, wenn angegeben, die temporäre Collection löscht, wenn der Iterator aufgebraucht ist (oder ein Fehler auftrat etc). Und eben auch, wenn der User das Resultat gar nicht benutzt. (Klar ist das ein Corner Case, ich hätte es aber trotzdem gerne.)

Der Code in question ist übrigens das hier: https://github.com/django-mongodb-engin ... t__.py#L68
BlackJack

@Dauerbaustelle: Ich kenne mich im Detail mit dem Code nicht aus, aber wo wird denn diese temporäre Collection erzeugt? In der Generatorfunktion? Dann wird sie dort doch nur erzeugt wenn Du das erste Element von dem Generator holst. Davor wird von der Funktion *nichts ausgeführt*!
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

BlackJack hat geschrieben:@Dauerbaustelle: Ich kenne mich im Detail mit dem Code nicht aus, aber wo wird denn diese temporäre Collection erzeugt? In der Generatorfunktion? Dann wird sie dort doch nur erzeugt wenn Du das erste Element von dem Generator holst. Davor wird von der Funktion *nichts ausgeführt*!
Ups. Peinlicher Denkfehler. Klar. Danke!
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Dauerbaustelle hat geschrieben:Der Generator iteriert über das Resultat einer Map/Reduce-Operation auf MongoDB, das in einer temporären Collection (das MongoDB-Äquivalent zu Tabellen, falls du dich damit nicht auskennst) gespeichert wird. Jetzt möchte ich ein Argument `drop_collection` anbieten, das, wenn angegeben, die temporäre Collection löscht, wenn der Iterator aufgebraucht ist (oder ein Fehler auftrat etc). Und eben auch, wenn der User das Resultat gar nicht benutzt. (Klar ist das ein Corner Case, ich hätte es aber trotzdem gerne.)
Bedenke aber auch den Fall, dass der Interpreter crashed und finally dann nicht ausgeführt wird.
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Darii hat geschrieben:Bedenke aber auch den Fall, dass der Interpreter crashed und finally dann nicht ausgeführt wird.
Jagut, soo wichtig ist das Aufräumen dann auch nicht. ;-)
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Wie will man mit *einem* Pythonscript über sichergehen das irgendwas aufgeräumt wird, wenn der Interpreter crashed. Dazu müsste man ja ein zweites Programm haben, welches den Interpreter überwachten, oder? Und wie kann man dann erkennen an welcher Stelle dieser abgekratzt ist?
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Xynon1 hat geschrieben:Wie will man mit *einem* Pythonscript über sichergehen das irgendwas aufgeräumt wird, wenn der Interpreter crashed.
Z.B. indem man vor jedem Durchlauf prüft ob noch alte temporäre Tabellen existieren. Oder man lässt das den Server erledigen, der die temporäre Tabelle löscht, wenn die Verbindung abbricht.
Antworten