简体   繁体   English

在基类和派生类中使用基类的装饰器

[英]Using decorator from base class both in base class and derived class

I have some python objects with some methods in which i would like to do some check at the beggining, depending of this check, the method's code would run, or an execption would be raised. 我有一些带有某些方法的python对象,在这些方法中,我希望在开始时进行一些检查,根据此检查,方法的代码将运行,或者将引发执行。 Instead of replicating the "check" code at the beginning of every method I though of doing a decorator, I also want the decorator to be embedded inside the class itself, since it is closely related to it. 我不希望在做装饰器时在每个方法的开头都复制“检查”代码,我还希望将装饰器嵌入到类本身中,因为它与之密切相关。 So basically: 所以基本上:

instead of this 代替这个

class A(object):

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

I would like to have this 我想要这个

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)

My first question is, am I going about this right? 我的第一个问题是,我要这样做吗? or is there a better way. 或者,还有更好的方法。 I have many methods of the A class that need to have this check, so that is why I don't want to replicate the code unnecessarily. 我有许多A类的方法需要进行检查,因此这就是为什么我不想不必要地复制代码的原因。

My second question is, if I go about this the way I described, I run into a problem when I want to derive a class from class A and performe the same decorator checks. 我的第二个问题是,如果按照我的描述进行操作,当我想从A类派生一个类并执行相同的装饰器检查时,就会遇到问题。 Again I don't want to replicate the code, so I want to reuse the decorator in the base class A to performe checks in the derived class. 再一次,我不想复制代码,所以我想重用基类A中的装饰器,以在派生类中执行检查。 I read about turning the decorator into a @classmethod however when I do this I am able to use the decorator in the derived class but not in the base class anymore! 我读过有关将装饰器转换为@classmethod但是当我这样做时,我可以在派生类中使用装饰器,而不再在基类中使用装饰器!

So basically I would like something like this: 所以基本上我想要这样的事情:

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)

Does anybody know of any clean way to do this? 有人知道有任何干净的方法吗?

Since you would prefer to put the decorator inside the class (rather than outside both of them as I suggested in a comment), below shows a way to do it. 由于您希望将装饰器放置在类中(而不是像我在评论中所建议的那样,将它们放置在类中),因此下面显示了一种实现方法。 It makes the decorator a staticmethod instead of a classmethod , and requires using it in a slightly unusual manner, but only within the class. 它使装饰器成为staticmethod classmethod ,而不是classmethod ,并要求以一种稍微不寻常的方式使用它,但仅使用。

For more information regarding the necessity of using the decorator like this, see my question Calling class staticmethod within the class body? 有关使用这样的装饰器的必要性的更多信息,请参阅我的问题在类主体中调用类staticmethod?

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')

One way to avoid having to use __func__ and still keep the definition in the first class would be to postpone turning it into a staticmethod until the very end of the class definition: 避免使用__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')

Yet another way to avoid the __func__ is something like this: 避免__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')

Which has the additional advantage of making usage of the decorator very uniform. 这具有使装饰器的使用非常均匀的附加优点。

My first question is, am I going about this right? 我的第一个问题是,我要这样做吗?

As martineau said below, the good practice is put classic decorator outside class. 正如martineau在下面说的那样,好的做法是将经典装饰器放在课外。

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)

Classic decorator is called during class creation time, which is long before an instance is created. 经典装饰器在类创建期间被调用,该创建时间比创建实例早。 Reference 参考

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM