Overwrite built-in function
Solution 1
This changes the behavior of the print
statement without forcing you to change
print "foo"
to
print("foo")
import sys
_stdout = sys.stdout
class MyStream(object):
def __init__(self, target):
self.target = target
def write(self, s):
s = 'Foo : {!r}'.format(s)
self.target.write(s)
sys.stdout = MyStream(sys.stdout)
print 'Hi'
sys.stdout = _stdout # return print to its old behavior
yields
Foo : 'Hi'
This could be neatened with a context manager, but if you don't want to change your print
statements into print
functions, you probably don't want to have to wrap your print
statements in a context manager either.
So, a better, a more civilized way would be to use
2to3 --write --fix print test.py
to automatically change all the print
statements in your code (e.g. test.py above) into print
functions. Then you can change the behaviour by redefining the print
function:
from __future__ import print_function
import __builtin__
def print(*args, **kwargs):
__builtin__.print('Foo:', *args, **kwargs)
print('Hi')
yields
Foo: Hi
Solution 2
Python directly supports what you want to do:
from __future__ import print_function
Any module with that line at the top will treat the print
statement as a function instead, making the code compatible with both Python 2 and 3.
This applies just to the print
statement; you cannot override other statements.
This does mean you then have to use print()
as a function everywhere in that module, but you can then also provide your own implementation if you so desire:
from __future__ import print_function
import __builtin__
def print(*args, **kwargs):
__builtin__.print('Prefixed:', *args, **kwargs)
print('Hello world!')
Another option is to use a context manager to capture printed statements, directing the output away from sys.stdout
into a in-memory file object of your choosing:
from contextlib import contextmanager
import sys
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
@contextmanager
def capture_sys_output():
caputure_out = StringIO()
current_out = sys.stdout
try:
sys.stdout = caputure_out
yield caputure_out
finally:
sys.stdout = current_out
and wrap any blocks that you want to capture print
output for with the context manager. Here is an example prefixing printed lines:
with capture_sys_output as output:
print 'Hello world!'
output = output.get_value()
for line in output.splitlines():
print 'Prefixed:', line
or even provide a wrapper:
from contextlib import contextmanager
import sys
class Prefixer(object):
def __init__(self, prefix, orig):
self.prefix = prefix
self.orig = orig
def write(self, text):
self.orig.write(self.prefix + text)
def __getattr__(self, attr):
return getattr(self.orig, attr)
@contextmanager
def prefix_stdout(prefix):
current_out = sys.stdout
try:
sys.stdout = Prefixer(prefix, current_out)
yield
finally:
sys.stdout = current_out
and use as:
with prefix_stdout('Prefixed: '):
print 'Hello world!'
but take into account that print
statements usually write data to stdout
in separate chunks; the newline at the end is a separate write.
Solution 3
In Python 2.x, print
is a statement and so it can be called without parens. Apparently you're using that.
You can't overwrite the built-in print statement.
However, it writes its output to sys.stdout
. Perhaps you can overwrite sys.stdout with some object that has a .write method, like this:
import sys
from StringIO import StringIO
s = StringIO()
sys.stdout = s
print "Hmmm."
assert s.getvalue() == "Hmmm.\n"
Solution 4
In Python 2, there is the print statement, which is a language construct. As such, you won’t be able to overwrite its behavior.
In Python 3, and in Python 2 if you enable it explicitely, you have the print function. It does require the parentheses, so print "foo"
will not work, but you can redefine what it does:
>>> from __future__ import print_function # for Python 2
>>> oldPrintFunction = print
>>> def print (*args, **kwargs):
oldPrintFunction('I am a changed print function')
oldPrintFunction(*args, **kwargs)
>>> print('foo')
I am a changed print function
foo
Admin
Updated on June 21, 2022Comments
-
Admin almost 2 years
I have a large chunk of code which uses the "print" statement. As to say in this way:
print "foo"
and not
print("foo")
I want to alter the output. Can I do this without changing all the lines with print? For example by overwriting the function/statement?
-
Martijn Pieters over 10 yearsActually, you can. Just the
print
statement, mind you, but you can. -
Martijn Pieters over 10 years@RemcoGerlich: Yes it is, really.
-
RemcoGerlich over 10 yearsAhh, and then he can go ahead and overwrite the builtin. I'd still prefer switching sys.stdout, but who knows.
-
Maciej Gol over 10 yearsNote that this will also alter all stdout operations done by the code called by that large chunk of code OP mentioned. This is not isolated only to the mentioned code's scope.
-
RemcoGerlich over 10 yearsThe problem is that in that case, he has to change all his print statements to use parens, and changing all his print statements is exactly what he's trying to avoid.
-
Martijn Pieters over 10 years@RemcoGerlich: But it'll be much easier to maintain than using a global 'swap out
stdout
' hammer. -
Maciej Gol over 10 years@RemcoGerlich, it's better to be explicit, and use the print function (and make a one-time effort of replacing the code), than face implicit consequences of changes global variables.
-
RemcoGerlich over 10 yearsIf he's already changing all the print()s, he can also change them to call his_own_custom_print() instead and doesn't need to overwrite anything, but he's asking how to avoid doing that work.
-
Maciej Gol over 10 years@RemcoGerlich, perhaps it could take more effort and time to do what the OP wants, fixing the side-effects on code called by the mentioned code, than replacing the strings and be on the safe side.
-
Martijn Pieters over 10 years@RemcoGerlich: you can name the override
print()
too.. -
Vincent over 10 yearsContext manager decorator... I like it!
-
HirsuteJim over 4 yearsPERFECT! Exactly what I wanted to do! Thank you.