【问题标题】:decorating methods causes method to pass in objects [duplicate]装饰方法导致方法传入对象[重复]
【发布时间】:2020-08-12 15:10:38
【问题描述】:

问题描述 我想使用装饰器来定义一个类方法,但这需要我在不需要提供时手动提供“自我”对象。

def func_wrapper(func): 
    def call_func(self):
        print(self.a)
        func()
    return call_func
def func():
    print('hello')

class test:
    def __init__(self, func):
        self.a = 0
        self.call_func = func_wrapper(func)

mytest = test(func)
#mytest.call_func() #why does this not work? 
mytest.call_func(mytest) #this works 

我希望能够 mytest.call_func() 但这不起作用,大概是因为 call_func 绑定到 func_wrapper 而不是 mytest。如果我手动传入对象,例如mytest.call_func(mytest) 这将起作用,但我不想手动传入对象 - 如果继承测试类并编写自己的 call_func 方法,这会创建不一致的调用签名,因为这样该方法将是正确的绑定到班级。

解决方案尝试

def func_wrapper2(func, obj): 
    def call_func():
        print(obj.a)
        func()
    return call_func
class test:
    def __init__(self, func):
        self.a = 0
        self.call_func = func_wrapper2(func, self)

这是一个解决方案,可以让我根据需要 test.call_func(),但这里 func_wrapper 不是真正的装饰器,因为它也需要在对象中传递。

在网上我发现这个博客https://medium.com/@vadimpushtaev/decorator-inside-python-class-1e74d23107f6 讨论了这个问题,并建议在嵌套类或辅助类中定义装饰器。但是,他们的解决方案似乎不起作用,并且我因传递错误数量的输入而出现类型错误。

class test2: 
    class test2helper: 
        @classmethod
        def func_wrapper(func):
            print(self.a)
            func()
    def __init__(self):
        self.a = 0
    @test2helper.func_wrapper
    def call_func(self):
        print('hello')

那么在类方法中使用装饰器的正确方法是什么?每种方法似乎都会导致如何处理自我的不同问题。除非有更好的方法,否则我将使用 func_wrapper2 设计。

【问题讨论】:

  • 在您的第一个 sn-p 中,self.call_func = func_wrapper(func).__get__(self, test)
  • 不要将方法分配给实例,在类级别进行。

标签: python


【解决方案1】:

你错过了一个级别:

class test2: 
    class test2helper: 
        @classmethod
        def decorator(cls, func):  # this must return a function!
            def func_wrapper(self):  # ... namely this one, the "wrapper"
                print(self.a)  # ... where you have access to the instance
                func(self)  # ... upon which the method is called
            return func_wrapper

    def __init__(self):
        self.a = 0

    @test2helper.decorator
    def call_func(self):
        print('hello')

>>> t = test2()
>>> t.call_func()
0
hello

或者,如果您想在没有嵌套类的情况下使用先前的尝试:

def decorator(func):  # you are decorating an unbound function!
    def func_wrapper(obj): 
        print(obj.a)
        func(obj)  # which has to be passed all the arguments
    return func_wrapper

class test:
    def __init__(self):
        self.a = 0

    @decorator
    def call_func(self):
        print('hello')

【讨论】:

    【解决方案2】:

    你可以定义一个 class 装饰器来做你想做的事:

    def class_decorator(cls):
        def call_func(self):
            print(self.a)
            return func()
    
        setattr(cls, 'call_func', call_func)
        return cls
    
    def func():
        print('hello')
    
    
    @class_decorator
    class Test:
        def __init__(self, func):
            self.a = 0
    
    
    mytest = Test(func)
    mytest.call_func()  # This now works.
    

    输出:

    0
    hello
    

    【讨论】:

      猜你喜欢
      • 2017-01-24
      • 2011-08-25
      • 2012-02-09
      • 1970-01-01
      • 1970-01-01
      • 2019-11-19
      • 1970-01-01
      • 2011-03-25
      • 1970-01-01
      相关资源
      最近更新 更多