我想在我的子类中实现一个父类装饰器,其功能取决于子类实例的状态。我试着从三个不同的角度来解决这个问题,但都没有奏效:
父方法
如果give_feedback
是一个静态方法,则该方法中没有self
。但是,如果它是一个实例方法,那么在应用它的命名空间中就没有self
。
class Interface:
def __init__(self, quiet=False):
self.quiet = quiet
def echo(self, text):
if not self.quiet:
print(text)
def give_feedback(self, func):
def wrapper(*args):
print('Calling give_feedback.')
self.echo(func(*args))
return wrapper
class App(Interface):
@Interface.give_feedback # self not defined here.
def app_func(self, num):
feedback = 'Success with {num}'.format(num=num)
return feedback
if __name__ == '__main__':
a = App()
a.app_func(3)
使用__call__的父类(参见链接example_1(
无法从__call__
中访问对象。
class Interface:
# ...
class give_feedback:
def __init__(self, func):
self.func = func
def __call__(self, *args):
print(
'Calling {func}'.format(func=self.func)
)
instance = get_obj_instance(self.func) # What is this?
return instance.echo(self.func(instance, *args))
class App(Interface):
# ...
if __name__ == '__main__':
# ...
父描述符(参见链接示例_2(
可以访问对象,但没有参数。
class Interface:
# ...
class give_feedback:
# ...
def __get__(self, instance, owner):
print(
'Getting {func} from {inst} of {ownr}'.format(
func=self.func, inst=instance, ownr=owner
)
)
num = 2 # How to get num???
return instance.echo(self.func(instance, num))
class App(Interface):
# ...
if __name__ == '__main__':
a = App()
a.app_func # No ability to pass parameters.
有好的方法吗?
为什么不组合第二种和第三种方法?使用__get__
获取类实例,使用__call__
用echo
进行装饰。与其返回app_func
,不如返回一个新对象,该对象包含实例并具有所需的__call__
行为。
class Interface:
def __init__(self, quiet=False):
self.quiet = quiet
def echo(self, text):
if not self.quiet:
print(text)
class give_feedback:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
return self.InstHolder(instance, self.func)
class InstHolder:
def __init__(self, inst, func):
self.inst = inst
self.func = func
def __call__(self, *args):
return self.inst.echo(self.func(self.inst, *args))
class App(Interface):
@Interface.give_feedback
def app_func(self, num):
feedback = 'Success with {num}'.format(num=num)
return feedback
if __name__ == '__main__':
a = App()
a.app_func(3)
a.quiet = True
a.app_func(4)