在Python中,如何使包装器同时适用于类和静态方法
我有几个名为在Python中,如何使包装器同时适用于类和静态方法,python,Python,我有几个名为parse的方法,它们要么是静态方法,要么是类方法。在这两种情况下,如果输入是None,我希望它们返回None。为此,我尝试定义以下包装器maybe: import types def maybe(function): if type(function) == types.FunctionType: def wrapped_function(arg, **kwargs): return function(arg, **kwargs)
parse
的方法,它们要么是静态方法,要么是类方法。在这两种情况下,如果输入是None
,我希望它们返回None
。为此,我尝试定义以下包装器maybe
:
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.")
下面是一个示例用例,附带一些测试:
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块的内容,尽管我已经通过print
语句验证了Boolean是False
如何使此包装器在两个测试中都能工作?您的方法实际上可以工作,但您犯了一个简单的键入错误,键入了
arg
,而不是*arg
。对于classmethod
,将传递一个额外的参数,该参数是cls
参数,只是arg
不同时接受cls
和None
,因此发生了错误arg
和*arg
确实有不同的含义,只是arg
代表给定位置的位置参数,而*arg
则接受位置参数未捕获的所有剩余参数。它的操作方式与**kwargs
获取所有剩余关键字参数的方式相同
因此,您应该将更改为以下内容:
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.")
强制在静态或类注释之后执行注释(将其放在代码上方)。然后,您可以检查函数/描述符的注释并决定如何处理它。例如
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"
这是针对Python3的。看起来您可能有Python2。所以它不能100%保证工作。您可能需要做更多的工作才能从类方法obj中获得原始函数