views:

137

answers:

4

Turns out with is a funny word to search for on the internet.

Does anyone knows what the deal is with nesting with statements in python?
I've been tracking down a very slippery bug in a script I've been writing and I suspect that it's because I'm doing this:

with open(file1) as fsock1:
    with open(file2, 'a') as fsock2:
        fstring1 = fsock1.read()
        fstring2 = fsock2.read()

Python throws up when I try to read() from fsock2. Upon inspection in the debugger, this is because it thinks the file is empty. This wouldn't be worrisome except for the fact that running the exact same code in the debugging interperter not in a with statement shows me that the file is in fact, quite full of text...

I'm going to proceed on the assumption that for now nesting with statements is a no-no, but if anyone who knows more has a different opinion, I'd love to hear it.

+5  A: 

AFAIK you can't read a file open with append mode 'a'.

Adam Bernier
I was just about to comment on my own question upon realizing the same thing. I feel... silly now.
Geoff
@Geoff: don't sweat it. Happens to us all.
Adam Bernier
+1  A: 

There is no problem with nesting with statements -- rather, you're opening file2 for append, so you can't read from it.

If you do dislike nesting with statements, for whatever reason, you can often avoid that with the contextlib.nested function. However, it won't make broken code (e.g., code that opens a file for append and then tries to read it instead) work, nor will lexically nesting with statements break code that's otherwise good.

Alex Martelli
+1  A: 

Upon inspection in the debugger, this is because it thinks the file is empty.

I think that happens because it can't actually read anything. Even if it could, when you append to a file, the seek pointer is moved to the end of the file in preparation for writing to occur.

These with statements work just fine for me:

with open(file1) as f:
    with open(file2, 'r') as g:   # Read, not append.
        fstring1 = f.read()
        fstring2 = g.read()

Note that use of contextlib.nested, as another poster suggested, is potentially fraught with peril here. Let's say you do this:

with contextlib.nested(open(file1, "wt"), open(file2)) as (f_out, f_in):
   ...

The context managers here get created one at a time. That means that if the opening of file2 fails (say, because it doesn't exist), then you won't be able to properly finalize file1 and you'll have to leave it up to the garbage collector. That's potentially a Very Bad Thing.

John Feminella
+1  A: 

As for searching for "with", prefixing a word with '+' will prevent google from ignoring it.

BlueRaja - Danny Pflughoeft
useful! Thank you.
Geoff