【问题标题】:Do something at the beginning & end of methods在方法的开头和结尾做一些事情
【发布时间】:2017-10-12 09:37:19
【问题描述】:

有没有一种简单的方法可以在类中每个函数的开头和结尾处执行某些操作?我已经查看了__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
    ...

【问题讨论】:

  • 只是想知道,你为什么要这样做?
  • @abccd 你的意思是他为什么要这样使用self.busy
  • 是的,我就是这个意思
  • 我在tkinter 做东西,我不希望鼠标或键盘输入打断任何东西

标签: python python-3.x class


【解决方案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)

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

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

【讨论】:

    【解决方案2】:

    你可以使用装饰器(如果你不知道可以参考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):
            ...
    

    【讨论】:

    • 开枪!,打败我 ;-)
    • 这很完美!谢谢!还有,是不是一定要叫decorator,还是随便叫什么?
    • @diligar 您可以随意称呼它。只要确保你给它的名字是有意义的。
    • 不,它不必被称为decorator。我只是这样命名它,因为我不是很有想象力。
    • 我只想补充一点,装饰器语法是some_fun = decorator(some_fun)的语法糖
    猜你喜欢
    • 2012-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    • 2012-08-21
    • 1970-01-01
    相关资源
    最近更新 更多