How to overload print function to expand its functionality?

不想你离开。 提交于 2020-12-01 10:22:05

问题


I am wondering if the build-in function print could be overridden so that the following statement will write to the console and a file at the same time.

print("test0","test1","test2",sep='\n') 

Also, may I know if it is possible to modify the source code of the build-in print function?


回答1:


You can create a class with a write method and inside of that method you can print both stdout as well as write to the file.

import sys

class A(object):
    def __init__(self, f):
        self.f = open(f, 'w') 

    def __enter__(self):
        return self   # return instance of A which is assign to `f`.

    def write(self, text):
        sys.stdout.write(text)  # print to the shell
        self.f.write(text) # write in the file

    def __exit__(self, *args):
        self.f.close()
        return True

with A('foo.txt') as f:
    print("test0","test1","test4",sep='\n', file=f) #`file = f` calls `write` method



回答2:


Use a decorator. Simplified example:

def my_decorator(func):
    def wrapped_func(*args,**kwargs):
        return func("I've been decorated!",*args,**kwargs)
    return wrapped_func

print = my_decorator(print)

Test:

print("TESTING") #I've been decorated! TESTING

So to print to a file at the same time you might do:

def super_print(filename):
    '''filename is the file where output will be written'''
    def wrap(func):
        '''func is the function you are "overriding", i.e. wrapping'''
        def wrapped_func(*args,**kwargs):
            '''*args and **kwargs are the arguments supplied 
            to the overridden function'''
            #use with statement to open, write to, and close the file safely
            with open(filename,'a') as outputfile:
                outputfile.write(*args,**kwargs)
            #now original function executed with its arguments as normal
            return func(*args,**kwargs)
        return wrapped_func
    return wrap

print = super_print('output.txt')(print)

If you compare this to the example above, you'll see there is an additional closure in this situation (i.e., return wrapped_func AND return wrap instead of just return wrapped_func). This second closure allows us to send an additional argument (filename) into the wrapper/decorator function.

The syntax of this last line looks a little weird, but this is the correct way. The call to super_print('output.txt') returns an object which is then given the print function object as an additional argument. This whole thing works via closures; research them if you aren't up to speed.

Then:

print('test')

test will be written to console output and to output.txt.




回答3:


print function uses sys.stdout unless the explicit file parameter is given.

You could redirect sys.stdout to a file-like object that writes to a console and a file at the same time:

#!/usr/bin/env python3
import sys
from contextlib import redirect_stdout

class TeeFile: # write to multiple files at once
    def __init__(self, *files):
        self.files = files
    def write(self, data):
        for file in self.files:
            file.write(data)
    def flush(self):
        for file in self.files:
            file.flush()

with open('log', 'a') as log, redirect_stdout(TeeFile(log, sys.stdout)):
    print("test0", "test1", "test2", sep='\n')

redirect_stdout is introduced in Python 3.4 but it is easy to implement it on earlier versions.

You could replace builtins.print function if you want to replace the print function globally. Consider whether logging module provides a better solution than print function in your case.




回答4:


It's probably a little late for this answer, but I've created a package (https://github.com/phohenecker/stream-to-logger) that provides exactly what you are looking for, namely redirecting stdout+stderr to a file (in addition to the usual printing to the screen).

It's super-easy, you just have to add two lines to your code:

import streamtologger
streamtologger.redirect(target="./all-output.log")

You can install the package with pip:

pip install git+https://github.com/phohenecker/stream-to-logger


来源:https://stackoverflow.com/questions/27621655/how-to-overload-print-function-to-expand-its-functionality

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!