获取任何可调用对象的参数?

时间:2017-01-04 21:28:08

标签: python callable-object

我有兴趣获得一种获取可调用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)

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

2 个答案:

答案 0 :(得分:2)

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

  

接受各种python callables,从普通函数和类到functools.partial()个对象。

signature做了什么需要你的callable并从中构造一个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这样的内置函数,这并不总是可行的,其中一些函数没有公开适当的元数据来构造签名,from PEP 362

  

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

因此,虽然zip不是公开自身信息的类型,但其他类似于all

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

你很遗憾地要求try-except这些,没有别的办法可以做。

signature帮助程序处理的案例在引入它的implementation section of PEP 362中进行了枚举。

一般来说,{3}已经在Python 3中暂时推荐inspect.getargspec,建议的方法(如果你使用的是Python 3)就是使用Signature个对象提供的表示。

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

答案 1 :(得分:0)

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

另一个选项是signature,这有点复杂。