在开始时做一些事情&方法结束

时间:2017-05-13 01:26:21

标签: python python-3.x class

是否有一种简单的方法可以在课程中的每个函数的开头和结尾处执行某些操作?我调查了__getattribute__,但我认为在这种情况下我不能使用它吗?

以下是我正在尝试做的简化版本:

class Thing():
    def __init__(self):
        self.busy = False

    def func_1(self):
        if self.busy: 
            return None
        self.busy = True
          ...
        self.busy = False

    def func_2(self):
        if self.busy: 
            return None
        self.busy = True
          ...
        self.busy = False
    ...

2 个答案:

答案 0 :(得分:11)

您可以使用装饰器(如果您不了解它们,可以参考PEP-318):

def decorator(method):
    def decorated_method(self, *args, **kwargs):
        # before the method call
        if self.busy:
            return None
        self.busy = True

        # the actual method call
        result = method(self, *args, **kwargs)  

        # after the method call
        self.busy = False

        return result

    return decorated_method

class Thing():
    def __init__(self):
        self.busy = False

    @decorator
    def func_1(self):
        ...

    @decorator
    def func_2(self):
        ...

如果您希望装饰的方法看起来像"您可能希望使用functools.wraps。原始方法。 @decorator只是语法糖,你也可以明确地应用装饰器:

class Thing():
    def __init__(self):
        self.busy = False

    def func_1(self):
        ...

    func_1 = decorator(func_1)  # replace "func_1" with the decorated "func_1"

如果您真的想将它应用于所有方法,您还可以使用类装饰器:

def decorate_all_methods(cls):
    for name, method in cls.__dict__.items():
        if name.startswith('_'):  # don't decorate private functions
            continue 
        setattr(cls, name, decorator(method))
    return cls

@decorate_all_methods
class Thing():
    def __init__(self):
        self.busy = False

    def func_1(self):
        ...

    def func_2(self):
        ...

答案 1 :(得分:1)

作为已接受答案的替代方法,如果您希望此装饰仅适用于实例方法,则可以使用__getattribute__

class Thing(object):
    def __init__(self):
        self.busy = False

    def __getattribute__(self, name):
        attr = object.__getattribute__(self, name)
        if callable(attr) and not name.startswith('_') and attr.__self__ == self:
            attr = decorator(attr)

        return attr

    def func_1(self):
        # instance method will be wrapped by `decorator`
        ...

    @classmethod
    def class_func(cls):
        # class method will not be wrapped by `decorator`
        # when called using `self.`, `cls.` or `Thing.`.
        ...

    @staticmethod
    def static_func():
        # static method will not be wrapped by `decorator`
        # when called using `Thing.`.
        ...
  • 这需要object,并且不适用于Python 2中的旧式类。
  • callable已在Python 3.0中删除,但在3.2中返回。或者,可以使用isinstance(obj, collections.Callable)

如果您想以不同方式包装类方法和静态方法,可以从自定义type metaclass继承:

class Meta(type):
    def __getattribute__(*args):
        print("staticmethod or classmethod invoked")
        return type.__getattribute__(*args)


class Thing(object, metaclass=Meta):
    ...
    def __getattribute__(self, name):
        attr = object.__getattribute__(self, name)
        if callable(attr) and not name.startswith('_'):
            if attr.__self__ == self:
                attr = decorator(attr)
            else:
                attr = Meta.__getattribute__(Thing, name)

        return attr

以上metaclass=Meta是Python 3语法。在Python 2中,它必须定义为:

class Thing(object):
    __metaclass__ = Meta