F
Frank Bechmann
Eventually most of you will not learn much from this because it's just
another event in the 'default argument value gotcha' series, but
because it cost me some hours yesterday to spot this 'error' in a
famous python tool I thought it might still help other people to save
some time.
I tried to use some method which was documented to write to
'sys.stdout' per default so that changing 'sys.stdout' to bind to
another object should allow to get grip on the method's output. but
that didn't work - reason was that that 'sys.stdout' was used as
default argument value for the method. The following code describes it
better then my english can do, so as it seems for me, one should make
sure to use the 'f2' variant.
import StringIO, sys
def f1(msg, out=sys.stdout):
out.write("%s\n" % msg)
def f2(msg, out=None):
if not out:
out = sys.stdout
out.write("%s\n" % msg)
if __name__ == "__main__":
buf = sys.stdout = StringIO.StringIO()
f1("calling f1")
f2("calling f2")
data = buf.getvalue()
buf.close()
sys.stdout = sys.__stdout__
print "=========\n", data
results in:
calling f1 <-- written directly by 'f1'
========== => redirection didn't work
calling f2 <-- written from data stored in 'buf'
running the following greps on this machine brought only 2 possible
spots, but that doesn't mean too much since this is our gaming
computer with only a very basic python installation; eventually
someone with a real huge package list would bring up more hits:
$ find . -name '*.py' -exec grep -H '\bdef\b.*\(.*\=sys.stdout.*\)[
\t]*:' \{} \;$ find . -name '*.py' -exec grep -H '\bdef\b.*\(.*\=sys.stderr.*\)[
\t]*:' \{} \;descriptions=1, verbosity=1):
another event in the 'default argument value gotcha' series, but
because it cost me some hours yesterday to spot this 'error' in a
famous python tool I thought it might still help other people to save
some time.
I tried to use some method which was documented to write to
'sys.stdout' per default so that changing 'sys.stdout' to bind to
another object should allow to get grip on the method's output. but
that didn't work - reason was that that 'sys.stdout' was used as
default argument value for the method. The following code describes it
better then my english can do, so as it seems for me, one should make
sure to use the 'f2' variant.
import StringIO, sys
def f1(msg, out=sys.stdout):
out.write("%s\n" % msg)
def f2(msg, out=None):
if not out:
out = sys.stdout
out.write("%s\n" % msg)
if __name__ == "__main__":
buf = sys.stdout = StringIO.StringIO()
f1("calling f1")
f2("calling f2")
data = buf.getvalue()
buf.close()
sys.stdout = sys.__stdout__
print "=========\n", data
results in:
calling f1 <-- written directly by 'f1'
========== => redirection didn't work
calling f2 <-- written from data stored in 'buf'
running the following greps on this machine brought only 2 possible
spots, but that doesn't mean too much since this is our gaming
computer with only a very basic python installation; eventually
someone with a real huge package list would bring up more hits:
$ find . -name '*.py' -exec grep -H '\bdef\b.*\(.*\=sys.stdout.*\)[
\t]*:' \{} \;$ find . -name '*.py' -exec grep -H '\bdef\b.*\(.*\=sys.stderr.*\)[
\t]*:' \{} \;descriptions=1, verbosity=1):