4

我有兴趣获得一种通用方法来获取可调用 Python 对象所采用的参数和关键字参数列表。对于具有该功能的功能,这是直截了当的inspect.getargspec,例如:

import inspect
from functools import partial

def foo(*args, **kwargs):
    return args, kwargs

print(inspect.getargspec(foo))
>>ArgSpec(args=[], varargs='args', keywords='kwargs', defaults=None)

def bar(*args):
    return args

print(inspect.getargspec(bar))
>>ArgSpec(args=[], varargs='args', keywords=None, defaults=None)

但是,这在以下情况下会失败:

partial_function = partial(foo, kwarg="value")

inspect.getargspec(partial_function)
>>TypeError: <functools.partial object at 0x11748bc58> is not a Python function

class Foo(object):
    def __call__(self, *args, **kwargs):
        return args, kwargs

foo_instance = Foo()

inspect.getargspec(foo_instance)
>>TypeError: <__main__.Foo object at 0x116c13ed0> is not a Python function

inspect.getargspec(zip)
>>TypeError: <built-in function zip> is not a Python function

请注意,有一些方法可以获取偏函数和可调用对象的参数,即:

inspect.getargspec(partial_function.func)
>>ArgSpec(args=[], varargs='args', keywords='kwargs', defaults=None)

inspect.getargspec(foo_instance.__call__)
>>ArgSpec(args=['self'], varargs='args', keywords='kwargs', defaults=None)

但如果可能的话,我想要一种更通用的方法来获得这些结果。

4

2 回答 2

3

所有这些都可以通过使用inspect.signature辅助函数来处理,如其文档中所述:

接受范围广泛的 Python 可调用对象,从普通函数和类到functools.partial()对象。

signature它的作用是获取您的可调用对象并从中构造一个对象Signature

>>> from inspect import signature
>>> s = signature(Foo())  # class as shown in your example

参数现在位于实例 的parameters映射属性中:Signature

>>> s.parameters
mappingproxy({'args': <Parameter "*args">, 'kwargs': <Parameter "**kwargs">})

使用partial对象,您将获得相应的表示:

>>> def foo(a, b, c): pass
>>> p = partial(foo, c = 30)
>>> signature(p).parameters
<Signature (a, b, *, c=20)>

至于内置函数,例如zip,这并不总是可行的,其中一些函数不会公开适当的元数据来构造签名,来自PEP 362

在 Python 的某些实现中,某些函数可能是不可自省的。例如,在 CPython 中,定义的内置函数C不提供有关其参数的元数据。添加对它们的支持超出了此 PEP 的范围。

因此,虽然zip不是公开有关自身信息的类型,但其他类型是,例如all

>>> signature(all)
<Signature (iterable, /)>

不幸的是,您需要try-except这些,没有其他可以做的。

signature助手处理的案例在介绍它的实现部分中列举。PEP 362

一般来说,inspect.getargspec在 Python 3 中已经弃用了一段时间,建议的方法(如果您使用的是 Python 3,即)是使用通过Signature对象提供的表示。

如果在 Python 上2,我很确定您不能直接使用getargspec,您应该getfullargspec按照 Anttis 的回答建议使用。

于 2017-01-04T21:40:34.883 回答
0

getfullargspec也正确处理部分。它以前被弃用但未被弃用,因为它被认为对单源 Python 2/3 多语言代码非常有用。

另一种选择是signature有点复杂。

于 2017-01-04T21:50:01.407 回答