2017-03-23 16 views
1

parseといういくつかのメソッドは静的メソッドまたはクラスメソッドです。どちらの場合も、入力がNoneの場合、Noneを返すようにします。ここで Pythonでは、クラスメソッドと静的メソッドの両方のラッパーを作成する方法

import types 

def maybe(function): 
    if type(function) == types.FunctionType: 
     def wrapped_function(arg, **kwargs): 
      return function(arg, **kwargs) if arg is not None else None 
     return wrapped_function 
    elif type(function) == types.MethodType: 
     def wrapped_function(cls, arg, **kwargs): 
      return function(cls, arg, **kwargs) if arg is not None else None 
     return wrapped_function 
    else: 
     raise TypeError("The 'maybe' wrapper can wrap either a function or a method.") 

はそれに同行するためにいくつかのテストと例のユースケースである:この目的を達成するために、私は次のラッパー maybeを定義しようとしました

import pytest 

class Resource(object): 
    @classmethod 
    @maybe 
    def parse_class(cls, string): 
     pass 

    @staticmethod 
    @maybe 
    def parse_static(string): 
     pass 


'''Tests''' 
def test_maybe_parse_class(): 
    assert Resource.parse_class(None) == None 

def test_maybe_parse_static(): 
    assert Resource.parse_static(None) == None 


if __name__ == "__main__": 
    pytest.main([__file__]) 

問題は、第二のテストはして失敗したということです

TypeError: wrapped_function() takes exactly 1 argument (2 given) 

私がで検証したにも関わらず、Pythonはif type(function) == types.FunctionTypeブロックの内容を評価するか、[チェック]をしようとしているようですブール値がFalseであるという文。

どのようにしてこのラッパーを両方のテストで動作させることができますか?

答えて

1

は、静的またはクラスのアノテーション(コードで上記のそれを置く)後に行われるmaybe注釈を強制します。次に、関数/記述子の注釈を調べて、それをどうするかを決めることができます。例えば。

def maybe(wrapped): 

    if isinstance(wrapped, classmethod): 
     original_function = wrapped.__func__ 

     @classmethod 
     def wrapper(cls, arg): 
      if arg is None: 
       return None 
      else: 
       return original_function(cls, arg) 
     return wrapper 

    elif isinstance(wrapped, staticmethod): 
     original_function = wrapped.__func__ 

     @staticmethod 
     def wrapper(arg): 
      if arg is None: 
       return None 
      else: 
       return original_function(arg) 
     return wrapper 

    raise TypeError("expected classmethod or staticmethod") 

class Resource(object): 
    @maybe 
    @classmethod 
    def parse_class(cls, arg): 
     return "not none" 

    @maybe 
    @staticmethod 
    def parse_static(arg): 
     return "not none" 

これはPython 3用です。あなたはPython 2を使用しているようです。したがって、100%保証されているわけではありません。元の関数をクラスメソッドobjから取得するには、もっと多くの作業が必要になるかもしれません。

+0

ありがとう、Python 2で動作します。 –

1

単純な入力ミスを除いて、*argの代わりにargと入力すると、実際にはメソッドが機能します。 classmethodの場合、引数はclsで、余分な引数が渡されます。clsの引数は、clsNoneの両方を受け取り、エラーが発生するように設計されていません。 arg*argは実際には意味が異なります。ちょうどargは、指定された位置での位置引数を表し、*argは、位置引数によって捕捉されない残りの引数を取ります。残ったキーワード引数をすべて取って**kwargsと同じように動作します。

ですから、これにmaybeを変更する必要があります。

import types 

def maybe(function): 
    if type(function) == types.FunctionType: 
     def wrapped_function(*arg, **kwargs): # change here 
      return function(*arg, **kwargs) if arg is not None else None # change here 
     return wrapped_function 
    elif type(function) == types.MethodType: 
     def wrapped_function(cls, *arg, **kwargs): # change here 
      return function(cls, *arg, **kwargs) if arg is not None else None # and change here 
     return wrapped_function 
    else: 
     raise TypeError("The 'maybe' wrapper can wrap either a function or a method.") 
関連する問題