Python - 将类作为参数传递给该类中方法的装饰器?

时间:2017-10-02 22:37:34

标签: python decorator

我希望执行以下操作:

class A(object):
    def first_method(self):
        print "I'm the first method!"    

    @some_decorator(A.first_method)
    def second_method(self):
        print "I'm the second method!"

但我遇到了解析装饰器时A内部未定义的问题。我有什么方法可以在装饰器中引用A吗?或者,如果我只是通过装饰器,绑定方法first_method是否可以恢复first_method属于A

2 个答案:

答案 0 :(得分:1)

在python 3中,你可以说@some_decorator(first_method),它会起作用,因为所有方法都是类中的普通函数作为容器。

在python 2中,有一个复杂的绑定系统和unbound,instance-,class-和static方法。因此,您无法在类定义内部访问first_method(如果完全形成,则直到该类)。

一个小的解决方法是将该类拆分为两个类:

class BaseA(object):
    def first_method(self):
        print "I'm the first method!"    

class A(BaseA):
    @some_decorator(BaseA.first_method)
    def second_method(self):
        print "I'm the second method!"

不是所有案例的最佳解决方案,但可行。

另外,请记住,在两种情况下(py2& py3),装饰器将引用此处声明的first_method。如果任何后代类重新定义该方法,则新方法将不会在装饰器中使用;只会使用父母。

可能你根本不应该提到first_method。相反,只需在装饰器的包装器中接受self / cls第一个位置参数,然后在那里使用self.first_method / cls.first_method

import functools

def some_decorator(fn):
    @functools.wraps(fn)
    def wrapper(self, *args, **kwargs):
        first_method = self.first_method
        first_method()
        return fn(self, *args, **kwargs)
    return wrapper

class A(object):
    def first_method(self):
        print "I'm the first method of A!"    

    @some_decorator
    def second_method(self):
        print "I'm the second method!"


class B(A):
    def first_method(self):
        print "I'm the first method of B!"    


A().second_method()
# I'm the first method of A!
# I'm the second method!

B().second_method()
# I'm the first method of B!
# I'm the second method!

如果您想使该方法可配置:

def some_decorator(method_name):
    def decorator(fn):
        @functools.wraps(fn)
        def wrapper(self, *args, **kwargs):
            first_method = getattr(self, method_name)
            first_method()
            return fn(self, *args, **kwargs)
        return wrapper
    return decorator


class A(object):
    def first_method(self):
        print "I'm the first method of A!"    

    @some_decorator('first_method')
    def second_method(self):
        print "I'm the second method!"

class B(A):
    def first_method(self):
        print "I'm the first method of B!"    

答案 1 :(得分:0)

您可以将装饰器用作经典功能(不带@):

def some_decorator(arg):
    # ...
    pass


class A(object):
    def first_method(self):
        print("I'm the first method!")

    def second_method(self):
        print("I'm the second method!")


A.second_method = some_decorator(A.first_method)(A.second_method)