2

Python 3.3:我可以装饰一个函数以忽略所有与命名参数不匹配的位置参数吗?

import functools
def ignore_star_args():
    def wrapper(function_):
        @functools.wraps(function_)
        def wrapped(*f_args):
            return function_(/*only named args*/)
        return wrapped
    return wrapper

@ignore_star_args()
def list_args(a, b, *args):
    # two positional arguments
    return [a, b] + list(args)

>>> list_args(1, 2, "non-positional arg")
[1, 2]
4

1 回答 1

8

我认为您误解了您使用的术语。

参数是传递给函数调用的值。位置参数是没有关键字的参数。

参数函数定义中的名称。有三种不同的位置参数;总的来说,它们是包含*参数或裸*(如果有)的参数。

例如,在这段代码中:

def foo(a, b, c=3, d=4, *args, e, f=6, **kw): pass

foo(1, 2, d=3, c=4, e=5, g=7)

a, b, c, 和d都是位置或关键字参数args是一个可变位置参数e并且f关键字参数;并且kw是一个var-keyword 参数(没有仅位置参数的示例,因为它们不能出现在函数定义中;您必须编写 C/Java/.NET/RPython/whatever 扩展代码,或code手动创建对象才能获取它们。)

在调用中,12位置参数3, 4, 5, 和7关键字参数d, c, e, 和g关键字标识符

Python 会将两个位置参数匹配到前两个仅位置或位置或关键字参数,或者如果没有足够的位置参数,则匹配关键字参数到位置或关键字或具有相同名称的仅限关键字参数,如果未找到名称,则添加到 var-keyword 参数。所以,里面foo

a, b, c, d, args, e, f, kw = 1, 2, 4, 3, (), 5, 6, {'g': 7}

既然你已经了解了所有这些,让我坐下来有点困惑:有时 Python 使用不同的术语,“形式参数”而不是“参数”和“实际参数”而不是“参数”。您通常只能在源代码的最古老部分中找到这一点,但有时它会冒泡得更高。


所以,你要求什么忽略非位置参数。换句话说,您想接受但忽略关键字参数。这很简单:只需使用 var-keyword 参数接受它们,不要通过它们:

def wrapped(*args, **kwargs):
    return function_(*f_args)

但是,我认为您想问的是如何忽略与仅位置或位置或关键字参数不匹配的所有参数,位置或关键字。

为此,您需要检查包装函数的签名。

很难找到不同类型成员的确切参考,而且当你这样做时也很难理解……但幸运的是,inspect文档将所有内容汇总在一个方便的图表中。

你可以看到一个函数没有任何看起来像它的参数签名的东西……但它包含一个代码对象,它. 当然,代码对象是在 Python 只有 2 种参数时设计的,它们被称为“形式参数”而不是“参数”,因此您在这里想要的可能不是很明显co_argcount——但相信我,它是。

所以:

def wrapped(*args):
    return function_(*(args[:function_.__code__.co_argcount]))

根据您想要对关键字参数执行的操作(记住,它可能与命名的位置或关键字或仅位置参数匹配!),您可能还想用**kwand做一些事情co_varnames

于 2013-06-21T01:11:31.833 回答