64

Am I able to overload the print function and call the normal function from within? What I want to do is after a specific line I want print to call my print which will call the normal print and write a copy to file.

Also I don't know how to overload print. I don't know how to do variable length arguments. I'll look it up soon but overload print python just told me I can't overload print in 2.x which is what I am using.

slybloty
  • 6,346
  • 6
  • 49
  • 70

9 Answers9

71

For those reviewing the previously dated answers, as of version release "Python 2.6" there is a new answer to the original poster's question.

In Python 2.6 and up, you can disable the print statement in favor of the print function, and then override the print function with your own print function:

from __future__ import print_function
# This must be the first statement before other statements.
# You may only put a quoted or triple quoted string, 
# Python comments, other future statements, or blank lines before the __future__ line.

try:
    import __builtin__
except ImportError:
    # Python 3
    import builtins as __builtin__

def print(*args, **kwargs):
    """My custom print() function."""
    # Adding new arguments to the print function signature 
    # is probably a bad idea.
    # Instead consider testing if custom argument keywords
    # are present in kwargs
    __builtin__.print('My overridden print() function!')
    return __builtin__.print(*args, **kwargs)

Of course you'll need to consider that this print function is only module wide at this point. You could choose to override __builtin__.print, but you'll need to save the original __builtin__.print; likely mucking with the __builtin__ namespace.

user2357112
  • 260,549
  • 28
  • 431
  • 505
DevPlayer
  • 5,393
  • 1
  • 25
  • 20
  • If I try using this function in Python 2.7.3 I get a `line 7, in print return __builtins__.print(*args, **kwargs) AttributeError: 'dict' object has no attribute 'print'` error. What could be the problem? – loudandclear Apr 13 '13 at 23:20
  • Hmmm... I tested it with Python 2.7.2 and it worked. I've notice Python 2.7.4 was just released and there are a few bug fixes with _ _future _ _ and print_function Check out http://hg.python.org/cpython/file/9290822f2280/Misc/NEWS I have not tested 2.7.4 either. – DevPlayer Apr 17 '13 at 04:36
  • 2
    You should do `import __builtin__` and then `__builtin__.print` instead of using `__builtins__`, [see the explanation here](https://docs.python.org/2/reference/executionmodel.html). – rczajka Jul 29 '14 at 08:04
  • 1
    Thanks for noticing that rczajka. However in Python 3.x `__builtin__` has been renamed. it is not usable in that form now. Check out: [Post](http://stackoverflow.com/questions/9047745/where-is-the-builtin-module-in-python3-why-was-it-renamed) – DevPlayer Aug 07 '14 at 02:56
  • note: it has no effect on other modules that use `print` statement in Python 2. – jfs Oct 30 '14 at 17:45
  • Also this works in Python 3.4.2: `return __builtins__['print'](*args, **kwargs)` – DevPlayer Apr 28 '15 at 13:00
  • Note that this means you'll need to change all your `print "something"` statements into `print("something")` style. Still a good solution though. – Ronen Ness Jul 07 '16 at 01:00
  • In my un-edited answer I mentioned you could centralize your print() functionality throughout to your application by moving this code to _ _init_ _.py. – DevPlayer Jul 21 '16 at 02:49
  • Thanks to user2357122 for editing this post to include the "try: import _ _builtin_ _..." snippet. This comment is provided to help remove confusion regarding my comments to this answer. See orginal post for clarity. – DevPlayer Jul 21 '16 at 02:59
34

Overloading print is a design feature of python 3.0 to address your lack of ability to do so in python 2.x.

However, you can override sys.stdout. (example.) Just assign it to another file-like object that does what you want.

Alternatively, you could just pipe your script through the the unix tee command. python yourscript.py | tee output.txt will print to both stdout and to output.txt, but this will capture all output.

ʞɔıu
  • 47,148
  • 35
  • 106
  • 149
19
class MovieDesc:
    name = "Name"
    genders = "Genders"
    country = "Country"

 def __str__(self):
#Do whatever you want here
        return "Name: {0}\tGenders: {1} Country: {2} ".format(self.name,self.genders,self.country)

)
Wouter J
  • 41,455
  • 15
  • 107
  • 112
Yan
  • 1,569
  • 18
  • 22
12

I came across the same problem.

How about this:

class writer :
    def __init__(self, *writers) :
        self.writers = writers

    def write(self, text) :
        for w in self.writers :
            w.write(text)

import sys

saved = sys.stdout
fout = file('out.log', 'w')
sys.stdout = writer(sys.stdout, fout)
print "There you go."
sys.stdout = saved
fout.close()

It worked like a charm for me. It was taken from http://mail.python.org/pipermail/python-list/2003-February/188788.html

  • 3
    `saved = sys.stdout` is unnecessary, `sys.__stdout__` always holds the original `stdout`, so at the end just do `sys.stdout = sys.__stdout__`. – chown Nov 26 '11 at 22:06
  • 1
    saving the sys.stdout allows you to chain overrides; if you write straight to sys.__stdout__ you will bypass any logging frameworks or such you try and inject into the program. Its best to explicitly save the previous value of stdout. – Will Apr 09 '13 at 07:35
  • Is there a particular reason you open the log using `file()` instead of `open()`? [The documentation recommends against that.](https://docs.python.org/2/library/functions.html#file) – Eric Apr 15 '16 at 21:43
5

For a very simple example, as of Python3.4 (haven't tested with older versions) this works well for me (placed at top of module):

import time
def dprint(string):
  __builtins__.print("%f -- %s" % (time.time(), string))

print = dprint

Note, this only works if the string parameter is a str... YMMV

Guillaume Jacquenot
  • 11,217
  • 6
  • 43
  • 49
Troy E. Lanes
  • 122
  • 1
  • 3
3

In Python 2.x you can't, because print isn't a function, it's a statement. In Python 3 print is a function, so I suppose it could be overridden (haven't tried it, though).

Joonas Pulakka
  • 36,252
  • 29
  • 106
  • 169
3

Though you can't replace the print keyword (in Python 2.x print is a keyword), it's common practice to replace sys.stdout to do something similar to print overriding; for example, with an instance of StringIO.StringIO. This will capture all of the printed data in the StringIO instance, after which you can manipulate it.

cdleary
  • 69,512
  • 53
  • 163
  • 191
2

I answered the same question on a different SO question

Essentially, simplest solution is to just redirect the output to stderr as follows, in the wsgi config file.

sys.stdout = sys.stderr
Community
  • 1
  • 1
lprsd
  • 84,407
  • 47
  • 135
  • 168
1

just thought I'd add my idea... suited my purposes of being able to run sthg in Eclipse and then run from the (Windows) CLI without getting encoding exceptions with each print statement. Whatever you do don't make EncodingStdout a subclass of class file: the line "self.encoding = encoding" would then result in the encoding attribute being None!

NB one thing I found out during a day grappling with this stuff is that the encoding exception gets raised BEFORE getting to "print" or "write": it is when the parameterised string (i.e. "mondodod %s blah blah %s" % ( "blip", "blap" )) is constructed by... what??? the "framework"?

class EncodingStdout( object ):
    def __init__( self, encoding='utf-8' ):
        self.encoding = encoding

    def write_ln( self, *args ):
        if len( args ) < 2:
            sys.__stdout__.write( args[ 0 ] + '\n' )
        else:
            if not isinstance( args[ 0 ], basestring ):
                raise Exception( "first arg was %s, type %s" % ( args[ 0 ], type( args[ 0 ]) ))
            # if the default encoding is UTF-8 don't bother with encoding
            if sys.getdefaultencoding() != 'utf-8':
                encoded_args = [ args[ 0 ] ]
                for i in range( 1, len( args )):
                    # numbers (for example) do not have an attribute "encode"
                    if hasattr( args[ i ], 'encode' ):
                        encoded_args.append( args[ i ].encode( self.encoding, 'replace' ) )
                    else:
                        encoded_args.append( args[ i ])
                args = encoded_args
            sys.__stdout__.write( args[ 0 ] % tuple( args[ 1 : ] ) + '\n' )
        # write seems to need a flush
        sys.__stdout__.flush()

    def __getattr__( self, name ):
        return sys.__stdout__.__getattribute__( name )

print "=== A mondodod %s %s" % ( "été", "pluviôse, irritée contre la ville entière" ) 


sys.stdout = EncodingStdout()
sys.stdout.write_ln( "=== B mondodod %s %s", "été", "pluviôse, irritée contre la ville entière" )

# convenience method
def pr( *args ):
    sys.stdout.write_ln( *args )

pr( "=== C mondodod %s %s", "été", "pluviôse, irritée contre la ville entière" )
mike rodent
  • 14,126
  • 11
  • 103
  • 157