Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python open() append and read, file.read() returns empty string

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??

like image 889
AndrewSmiley Avatar asked Aug 03 '15 18:08

AndrewSmiley


People also ask

Does read () return a string Python?

read() on IO objects usually returns a string or a bytes object (unicode or str object in Python 2), depending on whether you read encoded or raw data.

Does read () return a string?

open() function returns a file object. Call read() method on the file object. read() method returns whole content of the file as a string.

What does open () read () do in Python?

Python has a built-in open() function to open a file. This function returns a file object, also called a handle, as it is used to read or modify the file accordingly. We can specify the mode while opening a file. In mode, we specify whether we want to read r , write w or append a to the file.

What does read () return in Python?

Python File read() Method The read() method returns the specified number of bytes from the file. Default is -1 which means the whole file.


2 Answers

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.

like image 145
Peterino Avatar answered Oct 13 '22 11:10

Peterino


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.

like image 45
Morgan Thrapp Avatar answered Oct 13 '22 11:10

Morgan Thrapp