2017-10-11 20 views
0

メソッドの前後にオブジェクトの状態を表示するためのものと、メソッドの後の内部クラステストを実行するためのもの引数もあります)。ここでpython - スタックデコレータによる関数引数の受け渡し

私の現在の試みの例:

import functools 

class Dog: 

    def __init__(self): 
     self.happy = False 
     self.has_stick = False 

    def __str__(self): 
     n = ' ' if self.happy else ' not ' 
     return "I'm%sa happy dog" % n 

    def _verbose(func): 
     fname = func.func_name 
     argnames = func.func_code.co_varnames[:func.func_code.co_argcount] 
     @functools.wraps(func) 
     def decorator(*args, **kwargs): 
      print "Before %s(%s):" % (fname, ', '.join(
       '%s=%r' % entry 
       for entry in zip(argnames, args)[1:] + kwargs.items())) 
      print args[0] 
      result = func(*args, **kwargs) 
      print "After %s(%s):" % (fname, ', '.join(
       '%s=%r' % entry 
       for entry in zip(argnames, args)[1:] + kwargs.items())) 
      print args[0] 
      return result 
     return decorator 

    def _test(printout): 
     def actual_decorator(func): 
      @functools.wraps(func) 
      def wrapper(*args, **kwargs): 
       self = args[0] 
       output = func(*args, **kwargs) 
       self._test_not_happy_without_stick(printout) 
       return output 
      return wrapper 
     return actual_decorator 

    def _test_not_happy_without_stick(self, printout): 
     if printout: 
      print "Is happy:", self.happy 
      print "Has stick:", self.has_stick 
     if self.happy and not self.has_stick: 
      print "ERROR" 

    @_test(True) 
    @_verbose 
    def finds_stick(self, good_stick): 
     print "I found a stick!" 
     self.happy = good_stick 
     self.has_stick = True 

if __name__ == '__main__': 
    fido = Dog() 
    fido.finds_stick(False) 

デコレータの順序は上記のように適用される場合、出力は次のようになります。

Before finds_stick(good_stick=True): 
I'm not a happy dog 
I found a stick! 
After finds_stick(good_stick=True): 
I'm a happy dog 
Is happy: True 
Has stick: True 

しかし、それが逆になった場合(Iとして次のように装飾された関数に渡される引数の名前と値が失われます。

Before finds_stick(): 
I'm not a happy dog 
I found a stick! 
Is happy: True 
Has stick: True 
After finds_stick(): 
I'm a happy dog 

デコレータのスタッキングが、引数がデコレータを通過するのを防ぐことができないようにするにはどうすればよいですか?

また、この問題に対処するためのより平凡な方法の提案にも満足しています。

答えて

0

この問題は、下位互換性が@functools.wrap()であったため、上記の必要性を満たすシグネチャは保持されませんでした(Python 3.4以降のように)。

decoratorパッケージを使用すると、hereのように目的の機能を使用することができます。

上記の正しいコードがある:出力と

import decorator 

class Dog: 

    def __init__(self): 
     self.happy = False 
     self.has_stick = False 

    def __str__(self): 
     n = ' ' if self.happy else ' not ' 
     return "I'm%sa happy dog" % n 

    @decorator.decorator 
    def _verbose(func, *args, **kwargs): 
     fname = func.func_name 
     argnames = func.func_code.co_varnames[:func.func_code.co_argcount] 
     print "Before %s(%s):" % (fname, ', '.join(
      '%s=%r' % entry 
      for entry in zip(argnames, args)[1:] + kwargs.items())) 
     print args[0] 
     result = func(*args, **kwargs) 
     print "After %s(%s):" % (fname, ', '.join(
      '%s=%r' % entry 
      for entry in zip(argnames, args)[1:] + kwargs.items())) 
     print args[0] 
     return result 

    def _test(printout): 
     @decorator.decorator 
     def wrapper(func, *args, **kwargs): 
      self = args[0] 
      output = func(*args, **kwargs) 
      self._test_not_happy_without_stick(printout) 
      return output 
     return wrapper 

    def _test_not_happy_without_stick(self, printout): 
     if printout: 
      print "Is happy:", self.happy 
      print "Has stick:", self.has_stick 
     if self.happy and not self.has_stick: 
      print "ERROR" 

    @_verbose 
    @_test(True) 
    def finds_stick(self, good_stick): 
     print "I found a stick!" 
     self.happy = good_stick 
     self.has_stick = True 

if __name__ == '__main__': 
    fido = Dog() 
    fido.finds_stick(True) 

Before finds_stick(good_stick=True): 
I'm not a happy dog 
I found a stick! 
Is happy: True 
Has stick: True 
After finds_stick(good_stick=True): 
I'm a happy dog 
関連する問題