6

Noticed an odd behavior when attempting to call read() on a file opened in a+ mode (Python 3.4.1)

As seen here
File mode for creating+reading+appending+binary
It's possible to open a file in read/append mode supposedly.

However
This code:

with open("hgrc", "a+") as hgrc:
            contents=hgrc.read()

returns contents={str}''. Which is unexpected based upon the answer posted above.
Now, the following code

with open("hgrc", "r+") as hgrc:
            contents=hgrc.read()

returns contents={str}'contents of hgrc.....', which is expected, but doesn't give us the option to append to the file.

According to the specs

https://docs.python.org/2/library/functions.html#open

Modes 'r+', 'w+' and 'a+' open the file for updating (reading and writing); note that 'w+' truncates the file. Append 'b' to the mode to open the file in binary mode, on systems that differentiate between binary and text files; on systems that don’t have this distinction, adding the 'b' has no effect.

Which means
When we open a file in a+ mode, we should be able to call read() on it and get the contents of the file back, correct? Thoughts? Opinions? Etc??

Community
  • 1
  • 1
AndrewSmiley
  • 1,933
  • 20
  • 32
  • 1
    see if my [answer here](http://stackoverflow.com/questions/31598929/reading-a-file-in-c-different-behavior-for-r-and-a-flags/31599072#31599072) helps. It's on the `C` thread, but it should apply just as well – Pynchia Aug 03 '15 at 18:37
  • It helps to actually remember to click the button (; – AndrewSmiley Aug 04 '15 at 14:10

2 Answers2

7

This is a Python 2 vs. Python 3 issue.

open() with a+ behaves differently in the two Python versions. (Note: You reveal you're using Python 3.4.1, but you're quoting the documentation for Python 2!)

(In fact, the behavior you're looking for (in "Which means") works as intended with Python 2. I think they changed the behavior, because "appending" means "file pointer at end of file" to many folks.)


Let's test this with Python3 ...

$ python3
Python 3.4.3 (default, Jul 28 2015, 18:20:59) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> lic = open('LICENSE', 'a+')
>>> lic.read()
''
>>> # Hmmm, no content? EOF, obviously. Let's reset the file pointer ...
>>> lic.seek(0)
0
>>> lic.read()
'Apache License\nVersion 2.0, January 2004\n...'

Same thing with Python2 ...

$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> lic = open('LICENSE', 'a+')
>>> lic.read()
'Apache License\nVersion 2.0, January 2004\n...'
>>> lic.seek(0)
>>> lic.read()
'Apache License\nVersion 2.0, January 2004\n...'

Conclusion: You're safe using the seek(0) always after opening a file with a+, regardless to which Python version you use. This seems to be specific to the a+ mode.


Why does a system call behave differently across two Python versions?

One would think file manipulation is a system call, hence it's handled by the operating system. This is different with Python, as it looks according to the Python documentation:

Note: Python doesn’t depend on the underlying operating system’s notion of text files; all the processing is done by Python itself, and is therefore platform-independent.

BTW, this behavior has been reported as a bug on the Python bug tracker.

Peterino
  • 15,097
  • 3
  • 28
  • 29
5

a+ opens the file at the end for appending. You need to call .seek(0) on it if you want to then read in its contents, but at that point you might as well just use r+, because that opens the file at the start.

Morgan Thrapp
  • 9,748
  • 3
  • 46
  • 67
  • .seek(0) works. I wanted to be able to open the file to append and conditionally append a line to that file if it does not already contain that line. Alternatively, I could go as simple as 'r' if I simply needed to read. Perfect. Thanks! – AndrewSmiley Aug 03 '15 at 18:35
  • Note that this is true only for Python 3. In Python 2 `a+` opens the file for appending, and rewinds the file pointer. Of course, a `.seek(0)` doesn't do any harm in Python 2, but it's not strictly needed. – Peterino Sep 26 '15 at 20:20
  • @Peterino I did not know that, I don't use 2.x much. Good to know, thank you! – Morgan Thrapp Sep 27 '15 at 15:34
  • seek doesnt work for me. still return empty string. i almost made the table flipped – greendino Mar 22 '20 at 09:53