.write() behavior

Alan Bawden alan at scooby-doo.csail.mit.edu
Fri Oct 31 21:32:32 CET 2014

Marko Rauhamaa <marko at pacujo.net> writes:

> Let me mention a related problem I ran into a couple of weeks ago.
> Linux's standard C library (glibc) implements fread(3) differently in
> RHEL 5 and RHEL 6/7. In RHEL 5, it blocks in a loop until it has read in
> the desired number of records. In RHEL 6 and 7, it appears to block
> until it can return at least one whole record.

By my reading of the POSIX standard, that latter behavior would be
incorrect.  The "RETURN VALUE" section of the POSIX description for
fread() starts:

   Upon successful completion, fread() shall return the number of
   elements successfully read which is less than nitems only if a read
   error or end-of-file is encountered. ...

If in whatever version of glibc comes with RHEL 6/7, it is the case that
a call to fread() can return less than the desired number of records,
and you have not reached EOF, and no read error has occurred, that would
be a serious bug.  The world is full of C programs that call fread() and
fwrite() without wrapping them in defensive
maybe-I-didn't-get-everything loops.

>> Am I missing something? There seem to be some primitive IO facilities
>> in Python 3 that make a distinction between blocking and non-blocking
>> mode, but that distinction doesn't seem to be available when I just
>> call open().

Since I wrote this, I have discovered and read PEP-3116, and using that
as a road-map to understanding the Python 3 documentation it is now
clear to me that in Python 3, if you have not gone out of your way to
enable non-blocking, a call to the .write() method on any object that
might normally be returned by a call to open(), will always write _all_
of your data (or raise an exception).  There is never any need for a
defensive loop.

As further evidence that this is the case, note that PEP-3116 says right
at the end of its "Rationale and Goals" section:

   ...  Programmers who don't want to muck about in the new I/O world
   can expect that the open() factory method will produce an object
   backwards-compatible with old-style file objects.

Since old-style file objects didn't return a count, this goal can only
be achieved if programmers are safe in _ignoring_ that count in Python 3.

I am relieved to discover that when I am finally able to port my Python
code from Python 2 to Python 3, I will not have to worry that .write()
might perform an incomplete write where it previously did not.

Alan Bawden

More information about the Python-list mailing list