默认参数装饰器 python

2024-02-23

Python 3.6

我正在尝试创建一个装饰器,自动将参数的字符串指定为默认值。

such as:

def example(one='one', two='two', three='three'):
    pass

相当于:

@DefaultArguments
def example(one, two, three):
    pass

这是我的尝试(不起作用..还..)DefaultArguments:

from inspect import Parameter, Signature, signature


class DefaultArguments(object):

    @staticmethod
    def default_signature(signature):
        def default(param):
            if param.kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.POSITIONAL_ONLY):
                return param.replace(default=param.name)
            else:
                return param
        return Signature([default(param) for param in signature.parameters.values()])

    def __init__(self, func):
        self.func = func
        self.sig = self.default_signature(signature(func))

    def __call__(self, *args, **kwargs):
        arguments = self.sig.bind(*args, **kwargs)
        return self.func(arguments)

静态方法default_signature为该函数创建所需的签名,但我很难将新签名分配给该函数。我正在尝试使用签名。bind我读过docs https://docs.python.org/3/library/inspect.html但我错过了一些东西。

EDIT

结合 Ashwini Chaudhary 的回答:

from inspect import Parameter, Signature, signature

class DefaultArguments(object):

    @staticmethod
    def default_signature(signature):
        def default(param):
            if param.kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.POSITIONAL_ONLY):
                return param.replace(default=param.name)
            else:
                return param
        return Signature([default(param) for param in signature.parameters.values()])

    def __init__(self, func):
        self.func = func
        self.sig = self.default_signature(signature(func))
        print(self.sig)

    def __call__(self, *args, **kwargs):
        ba = self.sig.bind(*args, **kwargs)
        ba.apply_defaults()
        return self.func(*ba.args, **ba.kwargs)

这似乎有效:

import inspect

def default_args(func):
    argspec = inspect.getfullargspec(func)

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        unpassed_positional_args = argspec.args[len(args):]
        kwargs.update((a, a) for a in unpassed_positional_args if a not in kwargs)
        return func(*args, **kwargs)

    return wrapper

它依赖于这样一个事实:您可以在 python 中通过关键字传递位置参数。例如如果你有一个函数:

def foo(a, b):
    ...

您完全有权利将其称为:

foo(b=1, a=2)

我的解决方案计算出您传递了多少个位置参数,并使用它来计算出哪些位置参数weren't通过了。然后我将这些位置参数名称添加到kwargs而是听写。

这里最酷的事情是,如果有人需要 python2.x,他们只需要更改getfullargspec to getargspec它应该可以正常工作。


关于速度的注意事项:

将我的解决方案与 Ashwini 的出色解释进行比较表明,简单的装饰器比使用 Signature 对象快大约 10 倍:

@default_args
def foo(a, b, c):
    pass

@DefaultArguments
def bar(a, b, c):
    pass

@default_arguments
def qux(a, b, c):
    pass

import timeit
print(timeit.timeit('foo()', 'from __main__ import foo'))  # 1.72s
print(timeit.timeit('bar()', 'from __main__ import bar'))  # 17.4s
print(timeit.timeit('qux()', 'from __main__ import qux'))  # 17.6

他的解决方案实际上更新了__signature__的功能(这真的很好)。原则上,你可以采取Signature创建逻辑并将其添加到我的解决方案中以更新__signature__但保留argspec实际计算的风格逻辑......

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

默认参数装饰器 python 的相关文章

随机推荐