Как перегрузить функцию печати, чтобы расширить ее функциональность?

Мне интересно, если встроенная функция print может быть переопределено, так что следующий оператор будет записывать в консоль и файл одновременно.

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

Также, могу ли я узнать, возможно ли изменить исходный код встроенного print функционировать?

4 ответа

Используйте декоратор. Упрощенный пример:

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

print = my_decorator(print)

Тестовое задание:

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

Таким образом, для печати в файл одновременно вы можете сделать:

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)

Если вы сравните это с примером выше, вы увидите, что в этой ситуации есть дополнительное закрытие (т.е. return wrapped_func А ТАКЖЕ return wrap вместо просто return wrapped_func). Это второе закрытие позволяет нам отправить дополнительный аргумент (filename) в функцию оболочки / декоратора.

Синтаксис этой последней строки выглядит немного странно, но это правильный путь. Призыв к super_print('output.txt') возвращает объект, который затем получает print Функциональный объект в качестве дополнительного аргумента. Все это работает через замыкания; исследуйте их, если вы не в курсе.

Затем:

print('test')

test будет записан в консольный вывод и в output.txt.

Вы можете создать класс с write метод и внутри этого метода вы можете print и то и другое stdout так же как write в файл.

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

print функция использует sys.stdout если явное file параметр задан.

Вы могли бы перенаправить sys.stdout в файлоподобный объект, который пишет в консоль и в файл одновременно:

#!/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 представлен в Python 3.4, но его легко реализовать в более ранних версиях.

Вы могли бы заменить builtins.print функция, если вы хотите заменить print функционировать глобально. Подумайте, logging Модуль обеспечивает лучшее решение, чем print функционировать в вашем случае.

Вероятно, уже немного поздно для этого ответа, но я создал пакет ( https://github.com/phohenecker/stream-to-logger), который предоставляет именно то, что вы ищете, а именно перенаправление stdout+stderr в файл (в дополнение к обычной печати на экран).

Это очень просто, вам просто нужно добавить две строки в ваш код:

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

Вы можете установить пакет с помощью pip:

pip install git+https://github.com/phohenecker/stream-to-logger
Другие вопросы по тегам