2017-05-13 3 views
11

クラス内の各関数の最初と最後に何か簡単な方法がありますか?私は__getattribute__を調べましたが、私はこの状況で使うことはできないと思いますか?メソッドの始めと終わりに何かをする

ここで私が何をしようとしているの簡易版です。

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

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を参照することができます)を使用することができます装飾されたメソッドを元のメソッドのように見せたい場合は、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 
関連する問題