Чтобы уточнить ответ @ Дана Д. , вы должны создать новый функциональный объект для замены оригинала, что-то вроде этого:
from types import FunctionType
def reroute_decorator(**kwargs):
def actual_decorator(func):
globals = func.__globals__.copy()
globals.update(kwargs)
new_func = FunctionType(
func.__code__, globals, name=func.__name__,
argdefs=func.__defaults__, closure=func.__closure__)
new_func.__dict__.update(func.__dict__)
return new_func
return actual_decorator
Единственный улов здесьчто обновленный функциональный объект - это only , который будет видеть все, что вы передали kwargs
, поскольку они будут подделаны в глобальные переменные. Кроме того, любые изменения, внесенные в модуль после вызова функции декоратора, не будут видны для декорированной функции, но это не должно быть проблемой. Вы можете пойти еще глубже и создать прокси-словарь, который позволит вам нормально взаимодействовать с оригиналом, за исключением ключей, которые вы явно определили, например, print
, но здесь это немного выходит за рамки.
IВы обновили вашу print
реализацию, чтобы она была немного более общей, и сделали ввод в функцию декоратора более питоническим (меньше MATLABy):
def my_print(*args, **kwargs):
print(*(str(x).upper() for x in args), **kwargs)
@reroute_decorator(print=my_print)
def my_func():
print('normally this print function is just a print function...')
print('but since my_func is decorated with a special reroute_decorator...')
print('it is replaced with a different function, and its args sent there.')
В результате:
>>> my_func()
NORMALLY THIS PRINT FUNCTION IS JUST A PRINT FUNCTION...
BUT SINCE MY_FUNC IS DECORATED WITH A SPECIAL REROUTE_DECORATOR...
IT IS REPLACED WITH A DIFFERENT FUNCTION, AND ITS ARGS SENT THERE.