简体   繁体   中英

How to get the signature parameters of a callable, or reliably determine when this is not possible?

The built-in int takes two parameters:

>>> print(int.__doc__)
int(x=0) -> integer
int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments
...

However, (in CPython 3.4.0) inspect.signature shows 0:

>>> len(inspect.signature(int).parameters)
0

in contrast with a user-defined function:

>>> def my_int(x, base=10):
...     return int(x, base)
... 
>>> len(inspect.signature(my_int).parameters)
2

The docs for inspect.signature do say:

Some callables may not be introspectable in certain implementations of Python. For example, in CPython, some built-in functions defined in C provide no metadata about their arguments.

But they also say:

Raises ValueError if no signature can be provided, and TypeError if that type of object is not supported.

So I am surprised that I did not get a ValueError and instead got what appears to be an incorrect signature.

Is there a way to reliably (and programmatically) determine when it is not possible to get the parameters for a callable with inspect ? That is, if I am given something like int , is there a way to distinguish between "this thing does not have any parameters" and "it is not possible to determine what parameters this thing has"?

There's an open bug report for this: http://bugs.python.org/issue23934

The problem is that if the obj passed to signature() is a 'type', and it doesn't have a user defined init or new , it just gives up and returns the signature for object , which has 0 parameters.

If the obj is in the builtins module, and it's a 'type', but not an Exception, there's a pretty good chance it's not going to work with signature() .

I came up with this workaround to find the problem objs... It's not particularly elegant, but it may be useful to you:

def count_params():
    output = {}
    for funcname in dir(builtins):
        f = getattr( builtins,funcname)
        if isinstance(f, type):
            try:
                paramcount = len(inspect.signature(f).parameters)
                output[funcname] = paramcount
            except:
                pass
                #print("%s is a %s" % (funcname, type(f)))
    return output

Output:

{'__loader__': 0,
 'bool': 0,
 'bytes': 0,
 'complex': 0,
 'enumerate': 0,
 'filter': 0,
 'float': 0,
 'frozenset': 0,
 'int': 0,
 'map': 0,
 'memoryview': 0,
 'object': 0,
 'range': 0,
 'reversed': 0,
 'slice': 0,
 'str': 0,
 'tuple': 0,
 'zip': 0}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM