interaction of mode 'r+', file.write(), and file.tell(): a bug or undefined behavior?

Alf P. Steinbach alfps at start.no
Thu Jan 28 10:00:37 EST 2010


* Anthony Tolle:
> On Jan 28, 7:12 am, Lie Ryan <lie.1... at gmail.com> wrote:
>> In the code:
>>
>> """
>> f = open('input.txt', 'r+')
>> for line in f:
>>     s = line.replace('python', 'PYTHON')
>>     # f.tell()
>>     f.write(s)
>> """
>> [snip]
> 
> My guess is that there are a few possible problems:
> 
> 1) In this case, writing to file opened with 'r+' without an explicit
> f.seek is probably not a good idea.  The file iterator (for line in f)
> uses a readahead buffer, which means you can't guarantee what the
> current file position will be.
> 
> 2) It may be necessary to do an explicit f.flush or f.close when
> writing to an 'r+' file.  In your case, the close should automatically
> happen when the f object falls out of scope, which tells me that were
> still looking at some other problem, like not using f.seek
> 
> 3) It is possible that f.tell implicitly flushes buffers used by the
> file object.  That would explain why uncommenting the f.tell causes
> the writes to show up.

As far as I understand it the behavior stems from CPython file operations being 
implemented fairly directly as forwarding to C library FILE* operations, and the 
C standard prescribes Undefined Behavior to the case above.

I think the Python language/library specification should specify the effect 
(perhaps just as UB, but anyway, specified).

For as it is, it may/will be different with different Python implementations, 
meaning that code that works OK with one implementation may fail with another 
implementation.



> What are you trying to accomplish?  Overwrite the original file, or
> append to it?  If you want to overwrite the file, it may be better to
> generate a new file, delete the old one, then rename the new one.  If
> you want to append, then it would be better to open the file with
> append mode ('a')

Cheers,

- Alf



More information about the Python-list mailing list