Python: я хочу украсить атрибут MethodType без изменения типа атрибута на FunctionType

Я хочу реализовать следующую функциональность без изменения типа (testObject) в FunctionType:

import functools class TestClass(object): def speak(self): print 'My Name is Test' def hello_decorator(func): @functools.wraps(func) def hello_func(*args , **kwargs): print 'Hello World' return func(*args , **kwargs) return hello_func testObject = TestClass() preDecoratedSpeak = hello_decorator(getattr(testObject , 'speak')) setattr(testObject , 'speak' , preDecoratedSpeak) testObject.speak() print type(testObject.speak) 

Вывод:

 Hello World My Name is Test <type 'function'> 

Есть ли способ украсить метод, сохраняя метод методом экземпляра MethodType?

Если вы не можете использовать сторонний модуль, такой как wrapt , тогда вы можете вручную развернуть и обернуть функцию в декораторе. Фактически, вы можете написать декоратор, который можно применить к декоратору, чтобы сделать это автоматически.

 def accepts_method(decorator): @functools.wraps(decorator) def decowrapper(func): if hasattr(func, "im_func"): return type(func)(decorator(func.im_func), func.im_self, func.im_class) else: return decorator(func) return decowrapper 

Теперь вы можете просто украсить свой декоратор:

 @accepts_method def hello_decorator(func): # etc. 

К сожалению, functools.wraps имеет несколько недостатков в python 2, многие из которых исправлены в python3.

Попробуйте вместо этого использовать wrapt :

Модуль wrapt очень сильно фокусируется на правильности. Поэтому он выходит за рамки существующих механизмов, таких как functools.wraps() чтобы гарантировать, что декораторы сохраняют интроспективность, подписи, возможности проверки типов и т. Д. Декораторы, которые могут быть построены с использованием этого модуля, будут работать в гораздо большем количестве сценариев, чем типичные декораторы, и обеспечивают более предсказуемые и последовательное поведение.

Я не уверен, но почему вы используете setattr и getattr вместо того, чтобы прямо украшать его так:

 TestClass.speak = hello_decorator(TestClass.speak) 

или непосредственно в классе:

 class TestClass(object): @hello_decorator def speak(self): print 'My Name is Test' 

оба сохраняют тип функции <type 'instancemethod'>

Есть ли какая-то причина для использования getattr и setattr в фактическом экземпляре? Вместо того, чтобы переписывать методы экземпляра, подкласс может быть более уместным.