Why is the fileinput.input object not lost when it goes out of scope?

In the following code, I would expect python to free fileinput.input when I return ing in the middle of my loop, as it is out of scope. However, when called again, my fileinput function tells me

 raise RuntimeError, "input() already active" 

Here is my code:

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

I would expect this behavior when using yield , but not when using return.

I am using Python 2.7.3.

Is there a way to force reset fileinput?

EDIT

When calling fileinput.close() before returning, it works. Why is this not done implicitly?

EDIT 2 : thanks @MatsLindh

Replacement

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

with

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

does what I want because it returns an object that goes out of scope in a certain way. I assumed that fileinput.input() does this, but no. It uses a global instance.

+5
source share
4 answers

There is nothing that can go beyond the scope - you call a function in the imported module, and fileinput is one of those modules that have a global state, since future calls to fileinput maps to a previously executed input call.

You can get around this by using the fileinput class fileinput , which will be recreated the next time func() called and with with this object.

Or - as you discovered by calling close() , which resets the state of the internal module.

+2
source

Therefore, you need to wrap fileinput.input() in the closing context manager ", which will ** provide * 8, called .close() when exiting the block with with ...: ::

 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 [..] 

Using the context manager for objects that implement the protocol; usually file objects, etc. you ensure that cleared operations are performed when you exit the with block.


Garbage collection can occur at any time; and there are conditions when objects are freed and cleared. If you want the file object to close when you exit the block, use with .

+3
source

When calling fileinput.close () before returning, it works. Why is this not done implicitly?

Because : Explicit is better than implicit.

Python does not in any way guarantee the semantics of block cleaning, i.e. the resource is not necessarily cleared immediately after leaving the scope. The CPython implementation uses conservative reference counting, so it might seem like it is. This is not true. That is why there is also circular garbage collection.

If you want to clear, do it explicitly:

 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 [..] 

A closing() shell is needed because FileInput objects - at least in python 2.7 - are not context managers, i.e. there is no __exit__() method.

+2
source

File-like objects are implicitly closed. In addition, FileInput does not support the with statement.

However, you can use the closing context manager:

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

I abbreviated the files=sys.argv[1] argument for brevity and the default sys.argv[1:] . I suppose this will do what you want anyway.

+2
source

All Articles