注意:我不是问常见的python decorator,而是问decorator设计模式。你知道吗
我想编写一个能够修改由具体组件调用的函数的装饰器,下面的代码示例说明了我的问题:
In [2]: class Animal:
...: def sound(self):
...: raise NotImplementedError
...:
...: def speak(self):
...: print(self.sound())
...:
In [3]: class Dog(Animal):
...: def sound(self):
...: return 'woof!'
...:
In [4]: class Bigfy:
...: def __init__(self, animal):
...: self.animal = animal
...:
...: def sound(self):
...: return self.animal.sound().upper()
...:
...: def speak(self):
...: return self.animal.speak()
...:
In [5]: dog = Dog()
...: dog.speak()
...:
woof!
In [6]: big_dog = Bigfy(Dog())
...: big_dog.sound()
...:
Out[6]: 'WOOF!'
In [7]: big_dog.speak()
woof! # I want 'WOOF!' here
我想要增强功能的方法是sound
,但是这个方法不是由客户机直接调用的,而是由speak
在内部调用的,因此sound
上的所有包装都没有效果。你知道吗
使用decorator设计模式是否可能达到我想要的效果?如果不是什么设计模式,我应该看看?你知道吗
编辑:感谢大家的快速回答,按照@FHTMitchell的模式,我得出了以下解决方案:
In [1]: import inspect
In [2]: class Animal:
...: def sound(self):
...: raise NotImplementedError
...:
...: def speak(self):
...: print(self.sound())
...:
...: # Key change
...: @property
...: def unwrapped(self):
...: return self
...:
In [3]: class Dog(Animal):
...: def sound(self):
...: return 'woof!'
...:
In [4]: class BaseWrapper:
...: def __new__(cls, animal, **kwargs):
...: self = super().__new__(cls)
...: self.__init__(animal, **kwargs)
...:
...: # Automatically points unwrapped methods to last wrapper
...: for attr in dir(animal):
...: # Don't get magic methods
...: if attr.startswith('__') or attr.startswith('old'):
...: continue
...:
...: value = getattr(animal, attr)
...: if inspect.ismethod(value):
...: # Store old method
...: setattr(self, 'old_' + attr, value)
...: # Points to new method
...: setattr(animal.unwrapped, attr, getattr(self, attr))
...:
...: return self
...:
...: def __init__(self, animal):
...: self.animal = animal
...:
...: # Delegate all non-implemented attrs calls to wrapped class
...: def __getattr__(self, name):
...: return getattr(self.animal, name)
...:
...: # Helps with editor auto-completion
...: def __dir__(self):
...: dir_list = super().__dir__()
...: dir_list.extend(self.animal.__dir__())
...:
...: return dir_list
...:
In [5]: class Bigify(BaseWrapper):
...: def sound(self):
...: return self.old_sound().upper()
...:
In [6]: class Angrify(BaseWrapper):
...: def sound(self):
...: return self.old_sound() + '!!!'
...:
In [7]: class Happify(BaseWrapper):
...: def sound(self):
...: return self.old_sound() + ' =)'
...:
In [8]: big_angry_dog = Happify(Angrify(Bigify(Dog())))
...: big_angry_dog.speak()
...:
WOOF!!!! =)
简单方法
使用不同的设计模式使用动态属性:
那你就可以养条狗了
一个实例可能很大
而且是棕色的
复杂方式
如果确实要编辑实例方法,可以这样做(使用OP中的模式)
相关问题 更多 >
编程相关推荐