-
-
Notifications
You must be signed in to change notification settings - Fork 32.5k
Description
Documentation
The current function definition for the print()
builtin at https://docs.python.org/3/library/functions.html#print reads:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
However, this suggests that the default value of file
is the original version of sys.stdout
at Python iniitialise time, not the current value of sys.stdout
at the time the function is called. I just stumbled across a package which does this (function body stripped down to the bare minimum to highlight the issue):
def myfunc(arg1, stream=sys.stdout):
print(arg1, file=stream)
This looks fine, but it conceals a subtle issue, which is revealed when the function is called like this:
with contextlib.redirect_stdout(sys.stderr):
myfunc("message")
Since contextlib.redirect_stdout
redefines sys.stdout
, but in myfunc
, the default value of stream
is the value of sys.stdout
at function definition time, so this snippet still sends the output "message" to sys.stdout
rather than sys.stderr
.
However, print()
does not do this: print looks up the current value of sys.stdout
every time it is called without file=...
specified. It instead behaves like the following corrected version of myfunc
:
def myfunc(arg1, stream=None):
if stream is None:
stream = sys.stdout
print(arg1, file=stream)
My suggestion, therefore, would be to modify the definition given to read:
print(*objects, sep=' ', end='\n', file=None, flush=False)
Most readers will be unaffected by the change, especially as the behaviour of the function when file=None
is specified is explicitly described in the second paragraph. But it hints that the best way to specify a default of sys.stdout
in a function is to have the default being None
and to assign sys.stdout
in the body of the function.
[Edit: fix name of contextlib
function.]