【问题标题】:How to implement instance-dependent functionality using parent class decorator?如何使用父类装饰器实现实例相关功能?
【发布时间】:2019-05-09 14:54:41
【问题描述】:

我想在我的子类中实现一个父类装饰器,其功能取决于子类实例的状态。我尝试从三个不同的角度来解决这个问题,但都没有奏效:


Parent method

如果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)

Parent class using __call__(参见链接示例_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__':
    # ...

Parent descriptor(参见链接示例_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.

有什么好办法吗?

【问题讨论】:

    标签: python decorator python-decorators


    【解决方案1】:

    为什么不结合第二种和第三种方法呢?使用__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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-24
      • 2019-01-29
      • 2019-02-03
      相关资源
      最近更新 更多