Определите внутреннюю функцию вне функции декоратора и используйте тот факт, что functools.partial
может быть выбран:
import concurrent.futures
import functools
def inner_with_print(*args, func=None, **kwargs):
print("LOOK", args, kwargs)
return func(*args, **kwargs)
def with_print(func):
result_func = functools.partial(inner_with_print, func=func)
return functools.wraps(func)(result_func)
def f(arg, kwarg):
print("f called")
g = with_print(f)
if __name__ == "__main__":
with concurrent.futures.ProcessPoolExecutor(max_workers=10) as executor:
[executor.submit(g, i, kwarg=i) for i in range(10)]
# LOOK (0,) {'kwarg': 0}
# called
# LOOK (1,) {'kwarg': 1}
# f called
# ...
Метаданные были скопированы правильно:
print(vars(g))
# {'__module__': '__main__', '__name__': 'f', '__qualname__': 'f', '__doc__': None, '__annotations__': {}, '__wrapped__': <function f at 0x7f3251f01430>}
РЕДАКТИРОВАТЬ: вышеуказанные работы , но, похоже, это не проблема с динамическими c декораторами. Все работает нормально, если вы измените g = with_print(f)
на f = with_print(f)
. Похоже, что рассол ищет __main__.f
динамически и находит g
, в результате functools.wraps
маги c.
EDIT2: functools.wraps
маги c фактически устанавливают __qualname__
до f
. Если вы установите его обратно на g
, то он будет работать нормально:
g.__qualname__ = "g"
Похоже, все это происходит, потому что вы использовали wraps
, но также изменили имя функции на g
.