7

Im trying to understand how to create a custom print function. (using python 2.7)

import sys
class CustomPrint():
    def __init__(self):
        self.old_stdout=sys.stdout #save stdout

    def write(self, text):
        sys.stdout = self.old_stdout #restore normal stdout and print
        print 'custom Print--->' + text
        sys.stdout= self # make stdout use CustomPrint on next 'print'
                         # this is the line that trigers the problem
                         # how to avoid this??


myPrint = CustomPrint()
sys.stdout = myPrint
print 'why you make 2 lines??...'

The code above prints this to console:

>>> 
custom Print--->why you make 2 lines??...
custom Print--->

>>> 

and i want to print only one line:

>>>    
1custom Print--->why you make 2 lines??...
>>>

But cant figure out how to make this custom print work , i understand that there's some kind of recursion that triggers the second output to the console (i use self.write , to assign stdout to self.write himself !)

how can i make this work ? or is my approach just completely wrong...

andsoa
  • 500
  • 1
  • 6
  • 11
  • related: [Redirect stdout to a file in Python?](http://stackoverflow.com/q/4675728/4279) – jfs Jan 27 '15 at 11:27

3 Answers3

6

It's not recursion. What happens is your write function is called twice, once with the text you expect, second time with just '\n'. Try this:

import sys
class CustomPrint():
    def __init__(self):
        self.old_stdout=sys.stdout

    def write(self, text):
        text = text.rstrip()
        if len(text) == 0: return
        self.old_stdout.write('custom Print--->' + text + '\n')

    def flush(self):
        self.old_stdout.flush()

What I do in the above code is I add the new line character to the text passed in the first call, and make sure the second call made by the print statement, the one meant to print new line, doesn't print anything.

Now try to comment out the first two lines and see what happens:

    def write(self, text):
        #text = text.rstrip()
        #if len(text) == 0: return
        self.old_stdout.write('custom Print--->' + text + '\n')
matan h
  • 900
  • 1
  • 10
  • 19
piokuc
  • 25,594
  • 11
  • 72
  • 102
  • Thanks , its working like it should :) didn't know that \n was added on a second pass ! sys.stderr.write(":".join("{0:b}".format(ord(c)) for c in text)) even added this line just to make sure and your right ^^ – andsoa Feb 20 '13 at 18:22
  • 1
    there's a small problem when using comma separated print: 'print var1, var2' Apparently the comma calls print for each 'var' and suppresses the addition of '\n' on the previous 'var' ! This can be solved by adding a tmp var on the customPrint class , that stores text , and only prints when text ends with '\n' – andsoa Feb 21 '13 at 13:24
4

One solution may be to use a context manager if it's localised.

#!/usr/bin/env python
from __future__ import print_function

from contextlib import contextmanager


#############################
@contextmanager
def no_stdout():
    import sys
    old_stdout = sys.stdout

    class CustomPrint():
        def __init__(self, stdout):
            self.old_stdout = stdout

        def write(self, text):
            if len(text.rstrip()):
                self.old_stdout.write('custom Print--->' + text)

    sys.stdout = CustomPrint(old_stdout)

    try:
        yield
    finally:
        sys.stdout = old_stdout


#############################
print("BEFORE")
with no_stdout():
    print("WHY HELLO!\n")
    print("DING DONG!\n")

print("AFTER")

The above produces:

BEFORE
custom Print--->WHY HELLO!
custom Print--->DING DONG!
AFTER

The code would need tidying up esp. around what the class should do WRT setting stdout back to what it was.

matan h
  • 900
  • 1
  • 10
  • 19
sotapme
  • 4,695
  • 2
  • 19
  • 20
1

How about doing from __future__ import print_function. This way you will use Python3 print function instead of print statement from Python2. Then you can redefine the print function:

def print(*args, **kwargs):
    __builtins__.print("Custom--->", *args, **kwargs)

There is a catch however, you will have to start using print function.

Fenikso
  • 9,251
  • 5
  • 44
  • 72
  • That would work , but my case i need to change the print output of some classes written with python 2.7 print :/ – andsoa Feb 20 '13 at 18:04