在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中获得原始函数