Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overwrite built-in function [duplicate]

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?

like image 890
user3099519 Avatar asked Dec 13 '13 13:12

user3099519


4 Answers

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
like image 73
unutbu Avatar answered Nov 16 '22 01:11

unutbu


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
like image 44
poke Avatar answered Nov 15 '22 23:11

poke


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.

like image 26
Martijn Pieters Avatar answered Nov 15 '22 23:11

Martijn Pieters


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"
like image 32
RemcoGerlich Avatar answered Nov 16 '22 00:11

RemcoGerlich