Это происходит, потому что ваши декораторы устанавливают атрибуты на обертках. Когда первый декодированный устанавливает атрибут на своей обертке, он передает оболочку второму декоратору, который добавляет другую оболочку поверх первой и устанавливает атрибут во вторую обертку. Таким образом, вы получаете вторую оболочку.
In [3]: def decorator_a(fn):
...: def wrapper(*args, **kwargs):
...: return fn(*args, **kwargs)
...: print("I'm setting the attribute on function {}".format(id(wrapper)))
...: setattr(wrapper, "attr1", True)
...: return wrapper
...:
In [4]: def decorator_b(fn):
...: def wrapper(*args, **kwargs):
...: return fn(*args, **kwargs)
...: print("I'm setting the attribute on function {}".format(id(wrapper)))
...: setattr(wrapper, "attr2", True)
...: return wrapper
...:
In [5]: first_time_decorated = decorator_a(lambda x: x)
I'm setting the attribute on function 4361847536
In [6]: second_time_decorated = decorator_b(first_time_decorated)
I'm setting the attribute on function 4361441064
Вы можете решить эту проблему, установив все атрибуты функции украшаются на обертке
In [14]: def decorator_a(fn):
...: def wrapper(*args, **kwargs):
...: return fn(*args, **kwargs)
...: setattr(wrapper, "attr1", True)
...: for attribute in set(dir(fn)) - set(dir(wrapper)):
...: setattr(wrapper, attribute, getattr(fn, attribute))
...: return wrapper
...:
In [15]: def decorator_b(fn):
...: def wrapper(*args, **kwargs):
...: return fn(*args, **kwargs)
...: setattr(wrapper, "attr2", True)
...: for attribute in set(dir(fn)) - set(dir(wrapper)):
...: setattr(wrapper, attribute, getattr(fn, attribute))
...: return wrapper
...:
In [16]: first_time_decorated = decorator_a(lambda x: x)
In [17]: second_time_decorated = decorator_b(first_time_decorated)
In [18]: second_time_decorated.attr1
Out[18]: True
In [19]: second_time_decorated.attr2
Out[19]: True
't1'«оборачивает»функцию' test', а затем 't2'«оборачивает» функция, возвращаемая 't1'. Поэтому 't2' должен ожидать, что функция * украшена * как ее параметр, а не' test'. –
Как стилистическая сторона, [стандарт PEP8] (https://www.python.org/dev/peps/pep-0008/#indentation) требует 4 пробелов для отступов. В то время как только 1 работает синтаксически, его действительно трудно читать и затрудняет обмен вашим кодом с другими. –
Да, я вижу, что это так. Если I dir (function) - вход t2, я вижу атрибуты t1. Однако, если I dir (test), я вижу только t2 (t1 стирается). – Sonny