Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python: change sys.stdout print to custom print function

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...

like image 305
andsoa Avatar asked Feb 20 '13 17:02

andsoa


2 Answers

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')
like image 135
piokuc Avatar answered Sep 21 '22 22:09

piokuc


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.

like image 44
sotapme Avatar answered Sep 23 '22 22:09

sotapme