2017-05-13 30 views
11

在类中的每个函数的开始和结束处是否有一种简单的方法?我已经看过__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 
    ... 
+1

想知道为什么要这样做? – abccd

+1

@abccd你的意思是他为什么要使用'self.busy'那样? –

+0

是的,这就是我的意思 – abccd

回答

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): 
     ... 
+2

拍摄!,打我吧;-) –

+0

这完美的作品!谢谢!此外,它必须被称为'装饰器',或者它可以被称为任何东西吗? – diligar

+0

@diligar你可以任意调用它。只要确保你给它的名字是有意义的。 –

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 
相关问题