在基类和派生类

时间:2016-11-10 13:17:11

标签: python python-decorators class-method

我有一些python对象,其中有一些方法我想在开始时进行一些检查,取决于这个检查,方法的代码会运行,或者会引发一个execption。而不是复制"检查"代码在每个方法的开头我虽然做了一个装饰器,但我也希望装饰器嵌入到类本身中,因为它与它密切相关。所以基本上:

而不是

class A(object):

    def a_method(self):
        if self.check_var is True:
            (some_code)
        else:
            raise Exception

我想要这个

class A(object):

    def decorator(function):
        def function_wrapper(self, *args, **kwargs):
            if self.check_var is True:
                return function(self, *args, **kwargs)
            else:
                raise Exception
        return function_wrapper

    @decorator
    def a_method(self):
        (some_code)

我的第一个问题是,我是否正确行事?或者,还有更好的方法。我有很多A类的方法需要进行此检查,这就是为什么我不想不必要地复制代码。

我的第二个问题是,如果我按照我描述的方式进行此操作,当我想从A类派生一个类并且执行相同的装饰器检查时,我会遇到问题。我再也不想复制代码,因此我想重用基类A中的装饰器来对派生类中的执行进行检查。我读过关于将装饰器变成@classmethod但是当我这样做时,我能够在派生类中使用装饰器而不再在基类中使用!

所以基本上我想要这样的东西:

class A(object):

    @classmethod #maybe
    def decorator(function):
        def function_wrapper(self, *args, **kwargs):
            if self.check_var is True:
                return function(self, *args, **kwargs)
            else:
                raise Exception
        return function_wrapper

    @decorator
    def a_method(self):
        (some_code)

class B(A):

    @decorator
    def b_method(self):
        (some_code)

有人知道有什么干净的方法吗?

2 个答案:

答案 0 :(得分:4)

由于您希望将装饰器放在类中(而不是像我在注释中建议的那样在它们之外),下面显示了一种方法。它使装饰器成为staticmethod而不是classmethod,并且需要以稍微不同寻常的方式使用它,但只有类中。

有关使用像这样的装饰器的必要性的更多信息,请参阅我的问题Calling class staticmethod within the class body?

class A(object):
    @staticmethod
    def decorator(function):
        def function_wrapper(*args, **kwargs):
            print('in function_wrapper')
            return function(*args, **kwargs)
        return function_wrapper

    @decorator.__func__  #### Note unusual decorator usage inside defining class
    def a_method(self):
        print('in a_method')

class B(A):
    @A.decorator  #### Normal decorator usage outside defining class
    def b_method(self):
        print('in b_method')

避免使用__func__并仍然将定义保留在第一个类中的一种方法是推迟将其转换为staticmethod,直到类定义的最后:

class A(object):
    def decorator(function):
        def function_wrapper(*args, **kwargs):
            print('in function_wrapper')
            return function(*args, **kwargs)
        return function_wrapper

    @decorator
    def a_method(self):
        print('in a_method')

    decorator = staticmethod(decorator)  #### convert for use outside this class

class B(A):
    @A.decorator
    def b_method(self):
        print('in b_method')

另一种避免__func__的方法是这样的:

class A(object):
    class Check:
        @staticmethod
        def decorator(function):
            def function_wrapper(*args, **kwargs):
                print('in function_wrapper')
                return function(*args, **kwargs)
            return function_wrapper

    @Check.decorator
    def a_method(self):
        print('in a_method')

class B(A):
    Check = A.Check

    @Check.decorator
    def b_method(self):
        print('in b_method')

另外一个优点是使装饰器的使用非常均匀。

答案 1 :(得分:0)

  

我的第一个问题是,我是否正确行事?

正如马蒂诺在下面所说,好的做法是把经典装饰师放在课外。

def get_decorator(function, argument):
    def function_wrapper(*args, **kwargs):
        if argument is True:
            return function(*args, **kwargs)
        else:
            raise Exception
    return function_wrapper

class A(object):
    def __init__(self):
        self.check_var = True
        self.a_method = get_decorator(self.a_method, self.check_var)
    def a_method(self):
        (whatever)

class B(A):
    def __init__(self):
        super(B, self).__init__()
        self.b_method = get_decorator(self.b_method, self.check_var)
    def b_method(self):
        (whatever)
  

在类创建期间调用经典装饰器,这是在创建实例之前很久。 Reference