2017-05-13 64 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 
相關問題