2015-06-19 9 views
5

Im folgenden Code würde ich erwarten, dass Python fileinput.input freigibt, wenn ich return bin in der Mitte meiner Schleife bin, wie es außerhalb des Bereichs geht. Wenn jedoch meine Funktion fileinput mich wieder anrufen sagtWarum wird das fileinput.input-Objekt nicht verloren, wenn es aus dem Geltungsbereich entfernt wird?

raise RuntimeError, "input() already active" 

Hier ist mein Code:

def func(inplace): 
    for line in fileinput.input(sys.argv[1], inplace=inplace): 
     [..] 
     if condition: 
      return True 
     [..] 

if func(False): 
    func(True) 

ich dieses Verhalten erwarten würde, wenn yield verwenden, aber nicht bei der Verwendung von Rückkehr.

Ich benutze Python 2.7.3.

Gibt es eine Möglichkeit, einen Reset des Fileinputs zu erzwingen?

EDIT:

Beim Aufruf fileinput.close(), bevor es wieder funktioniert. Warum wird es nicht implizit gemacht?

EDIT 2: Danke

Ersetzen

for line in fileinput.input(sys.argv[1], inplace=inplace): 

mit

for line in fileinput.FileInput(sys.argv[1], inplace=inplace): 

@MatsLindh tut, was ich will, weil es ein Objekt zurückgibt, die out-of-scope geht in einer definierten Weise. Ich nahm an, dass fileinput.input() das tut, aber nein. Es verwendet eine globale Instanz.

+0

Warum würden Sie das erwarten? Python garantiert keine Bereinigung am Blockende (es ist nur cpython, das dies normalerweise tut, aber nur, wenn es keine Referenzzyklen gibt). – dhke

+0

Müllsammlung kann jederzeit auftreten; und es gibt Bedingungen, wenn Objekte freigegeben und gereinigt werden. Wenn Sie möchten, dass das Dateiobjekt geschlossen wird, wenn Sie den Block verlassen, verwenden Sie '' '' –

+1

@JamesMills Ich denke, Sie sollten Ihren Kommentar eine Antwort geben. Es scheint so zu sein, IMHO. –

Antwort

2

Es gibt nichts, hier ist die den Gültigkeitsbereich verlassen können - Sie haben eine Funktion in einem Modul sind aufrufen, die importiert wurde, und fileinput ist eines dieser Module, die globalen Zustand hat, da zukünftige Anrufe zu fileinput Karten der vorhergehende input Anruf.

sollten Sie in der Lage sein, dies zu umgehen, indem die FileInput Klasse statt mit, die das nächste Mal func() rufen neu erstellt werden und durch with zusammen mit diesem Objekt.

Oder - wie Sie festgestellt haben, Aufruf close(), die den internen Modulstatus zurückgesetzt.

+0

Ich denke du nagelst es. Meine Annahme war, dass fileinput.input() ein Objekt zurückgibt. Was beim Verlassen der Schleife nicht möglich ist. –

3

So Sie Notwendigkeitfileinput.input() in einem closing "Kontext-Manager" zu wickeln, die ** gewährleisten * 8 dass .close() aufgerufen wird, wenn Sie den Block verlassen, indem with ...: mit:

from contextlib import closing 

def func(inplace): 
    with closing(fileinput.input(sys.argv[1], inplace=inplace)) as finput: 
     for line in finput: 
      [..] 
      if condition: 
       return True 
      [..] 

einen Kontext-Manager auf Objekten, die das Protokoll implementieren; in der Regel Dateiobjekte und dergleichen Sie sicherstellen, dass gereinigte Operationen am Ausgang des with Block durchgeführt werden.


Garbage collection kann jederzeit auftreten; und es gibt Bedingungen um, wenn Objekte freigegeben und gereinigt werden. Wenn das Dateiobjekt beim Beenden der Blockierung geschlossen werden soll, verwenden Sie with.

+3

'fileinput' ist ein [Standard-Python-Modul] (https://docs.python.org/2/library/fileinput.html), das den globalen Zustand über den vorherigen Aufruf von' input() 'für zukünftige Aufrufe an andere Dateieingaben behält Funktionen. – MatsLindh

+0

Ja; genau; Die ** Schlüssel ** Sache hier ist die Verwendung eines "Kontextmanagers". –

+0

'FileInput' (was von' input() 'zurückgegeben wird) implementiert nicht' __exit __() ', daher die Notwendigkeit für' closing() ' – dhke

2

Wenn fileinput.close() vor der Rückgabe aufgerufen wird, funktioniert es. Warum wird es nicht implizit gemacht?

Because: Explizit ist besser als implizit.

Python garantiert in keiner Weise Block-Cleanup-Semantik, d. H. Eine Ressource wird nicht unbedingt sofort bereinigt, wenn sie den Gültigkeitsbereich verlässt. Die CPython-Implementierung verwendet eine konservative Referenzzählung, so dass dies möglicherweise der Fall ist. Es ist nicht. Deshalb gibt es auch zyklische Garbage Collection.

Wenn Sie Bereinigungs wollen, tun Sie es ausdrücklich:

from contextlib import closing 

def func(inplace): 
    with closing(fileinput.input(sys.argv[1], inplace=inplace)) as finput: 
     for line in finput: 
      [..] 
     if condition: 
      return True 
     [..] 

Die closing() Wrapper benötigt wird, weil FileInput Objekte --at dest auf Python 2.7-- sind nicht Kontext-Manager, das heißt es gibt keine __exit__() Methode.

+0

Ich möchte Ihren Ausdruck erweitern: * Python garantiert in keiner Weise Block-Cleanup-Semantik * mit *, außer wenn Sie es richtig verwenden. * –

2

Dateiähnliche Objekte sind nicht implizit geschlossen. Außerdem unterstützt FileInput die with-Anweisung nicht.

Sie können jedoch den closing Kontext-Manager verwenden:

from contextlib import closing 

with closing(fileinput.input(inplace=inplace)) as input: 
    for line in input: 
     if condition: 
      return True 

Ich entfernte die files=sys.argv[1] Argument der Kürze und als Standard ist sys.argv[1:]. Ich nehme an, das wird immer noch tun, was du willst.

Verwandte Themen