如何获得装饰函数的参数规范?

Dav*_*mer 21 python

我需要确定装饰器中函数的argspec(inspect.getargspec):

def decor(func):
    @wraps(func)
    def _decor(*args, **kwargs):
        return func(*args, **kwargs)
    return _decor

@decor
def my_func(key=1, value=False):
    pass
Run Code Online (Sandbox Code Playgroud)

我需要能够检查包装的"my_func"并返回键/值参数及其默认值.看来inspect.getargspec没有得到正确的功能.

(对于一些运行时检查/验证以及后来的文档生成,我需要这个)

unu*_*tbu 14

如果您使用Michele Simionato的装饰器模块来装饰您的功能,decorator.decorator它将保留原始功能的签名.

import inspect
import decorator

@decorator.decorator
def decor(my_func,*args,**kw):
    result=my_func(*args,**kw)
    return result

@decor
def my_func(key=1, value=False):
    pass
decorated_argspec = inspect.getargspec(my_func)
print(decorated_argspec)
# ArgSpec(args=['key', 'value'], varargs=None, keywords=None, defaults=(1, False))
Run Code Online (Sandbox Code Playgroud)


Ooz*_*ter 5

我写了一个简单的类,可以做你想要的。这将实现与functools.wraps保留函数签名相同的功能(从getargspec的角度来看)。在我的要点上阅读该课程的文档字符串以获取更多信息

注意:这只适用于装饰函数,不适用于类方法。

import types

class decorator(object):
    def __getattribute__(self, name):
        if name == '__class__':
            # calling type(decorator()) will return <type 'function'>
            # this is used to trick the inspect module >:)
            return types.FunctionType
        return super(decorator, self).__getattribute__(name)

    def __init__(self, fn):
        # let's pretend for just a second that this class
        # is actually a function. Explicity copying the attributes
        # allows for stacked decorators.
        self.__call__ = fn.__call__
        self.__closure__ = fn.__closure__
        self.__code__ = fn.__code__
        self.__doc__ = fn.__doc__
        self.__name__ = fn.__name__
        self.__defaults__ = fn.__defaults__
        self.func_defaults = fn.func_defaults
        self.func_closure = fn.func_closure
        self.func_code = fn.func_code
        self.func_dict = fn.func_dict
        self.func_doc = fn.func_doc
        self.func_globals = fn.func_globals
        self.func_name = fn.func_name
        # any attributes that need to be added should be added
        # *after* converting the class to a function
        self.args = None
        self.kwargs = None
        self.result = None
        self.function = fn

    def __call__(self, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs

        self.before_call()
        self.result = self.function(*args, **kwargs)
        self.after_call()

        return self.result

    def before_call(self):
        pass

    def after_call(self):
        pass
Run Code Online (Sandbox Code Playgroud)

只需通过子类化创建一个新的装饰器

import time

class timeit(decorator):
    def before_call(self):
        self.start = time.time()
    def after_call(self):
        end = time.time()
        print "Function {0} took {1} seconds to complete.".format(
            self.__name__, end - self.start
        )

@timeit
def my_really_cool_function(a, b, c, d='asdf', q='werty'):
    time.sleep(5)
Run Code Online (Sandbox Code Playgroud)

像任何普通的装饰功能一样使用它

args = inspect.getargspec(my_really_cool_function)
print args

my_really_cool_function(1,2,3,4,5)
Run Code Online (Sandbox Code Playgroud)

输出

ArgSpec(args=['a', 'b', 'c', 'd', 'q'], varargs=None,
        keywords=None, defaults=('asdf', 'werty'))
Function my_really_cool_function took 5.0 seconds to complete.
Run Code Online (Sandbox Code Playgroud)