Как перегрузить функцию печати, чтобы расширить ее функциональность?
Мне интересно, если встроенная функция 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