Overwrite built-in function

13,305

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
Share:
13,305
Admin
Author by

Admin

Updated on June 21, 2022

Comments

  • Admin
    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
    Martijn Pieters over 10 years
    Actually, you can. Just the print statement, mind you, but you can.
  • Martijn Pieters
    Martijn Pieters over 10 years
    @RemcoGerlich: Yes it is, really.
  • RemcoGerlich
    RemcoGerlich over 10 years
    Ahh, and then he can go ahead and overwrite the builtin. I'd still prefer switching sys.stdout, but who knows.
  • Maciej Gol
    Maciej Gol over 10 years
    Note 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
    RemcoGerlich over 10 years
    The 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
    Martijn Pieters over 10 years
    @RemcoGerlich: But it'll be much easier to maintain than using a global 'swap out stdout' hammer.
  • Maciej Gol
    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
    RemcoGerlich over 10 years
    If 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
    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
    Martijn Pieters over 10 years
    @RemcoGerlich: you can name the override print() too..
  • Vincent
    Vincent over 10 years
    Context manager decorator... I like it!
  • HirsuteJim
    HirsuteJim over 4 years
    PERFECT! Exactly what I wanted to do! Thank you.