获取Python内置函数的parameter(arg)计数 [英] Get parameter(arg) count of builtin functions in Python
问题描述
我在文档中为Python和自定义表编写了自己的c模块.在运行时,我需要内置函数的参数数量.
I wrote my own c-module for Python and for a custom table in a documentation I need the number of parameters of the builtin-functions during runtime.
Python 2中有一些功能,例如 inspect.getargspec 或Python 3中的功能,如支持的 inspect.signature 正常的Python函数,但不支持内置函数.
There are functions in Python 2 like inspect.getargspec or functions in Python 3 like inspect.signature which support normal Python functions, but leave builtin-functions unsupported.
到目前为止,还有其他两种社区解决方案:
There are two other community solutions so far:
- 解析文档字符串
- 解析原始* .c文件
- 请参阅第三种方法的答案
在某些情况下,文档字符串已过时和/或难以提取参数计数,因为文档字符串可以是任何纯字符串.解析原始* .c文件也是一种很好的方法,但是您可能无法访问它.
In some cases the docstrings are outdated and/or it's hard to extract the argument count since the docstring can be any plain string. Parsing the original *.c file is a good approach as well, but you might not have access to it.
推荐答案
在下面,这是我针对Python 2和3提出的有效解决方案.
In the following this is the working solution I came up with for Python 2 and 3.
它做什么?
在运行时,将99个None对象的列表传递给相应的函数.内部解析函数PyArg_ParseTuple
中的第一个检查之一是检查参数数量是否与传递的参数数量匹配-如果不匹配,它将失败.这意味着我们将调用该函数,但也可以确保它不会真正执行.
During runtime a list of 99 None objects gets passed to the corresponding function. One of the first checks in the internal parsing function PyArg_ParseTuple
checks if the amount of parameters matches the amount of passed parameters - if not it will fail. That means we will call the function but we can also be sure it doesn't get really executed.
技术背景:
为什么很难获得内置函数的参数计数?问题在于参数列表是在运行时而不是编译时评估的. C中内置函数的一个非常简单的示例如下:
Why is it so hard to get the count of parameters of built-in functions? The problem is that the parameter list is evaluated during runtime, not compile time. A very simple example of a built-in function in C looks like this:
static PyObject* example(PyObject *self, PyObject *args)
{
int myFirstParam;
if(!PyArg_ParseTuple(args, "i", &myFirstParam))
return NULL;
...
}
复制和粘贴解决方案:
import inspect
import time
import re
import types
import sys
def get_parameter_count(func):
"""Count parameter of a function.
Supports Python functions (and built-in functions).
If a function takes *args, then -1 is returned
Example:
import os
arg = get_parameter_count(os.chdir)
print(arg) # Output: 1
-- For C devs:
In CPython, some built-in functions defined in C provide
no metadata about their arguments. That's why we pass a
list with 999 None objects (randomly choosen) to it and
expect the underlying PyArg_ParseTuple fails with a
corresponding error message.
"""
# If the function is a builtin function we use our
# approach. If it's an ordinary Python function we
# fallback by using the the built-in extraction
# functions (see else case), otherwise
if isinstance(func, types.BuiltinFunctionType):
try:
arg_test = 999
s = [None] * arg_test
func(*s)
except TypeError as e:
message = str(e)
found = re.match(
r"[\w]+\(\) takes ([0-9]{1,3}) positional argument[s]* but " +
str(arg_test) + " were given", message)
if found:
return int(found.group(1))
if "takes no arguments" in message:
return 0
elif "takes at most" in message:
found = re.match(
r"[\w]+\(\) takes at most ([0-9]{1,3}).+", message)
if found:
return int(found.group(1))
elif "takes exactly" in message:
# string can contain 'takes 1' or 'takes one',
# depending on the Python version
found = re.match(
r"[\w]+\(\) takes exactly ([0-9]{1,3}|[\w]+).+", message)
if found:
return 1 if found.group(1) == "one" \
else int(found.group(1))
return -1 # *args
else:
try:
if (sys.version_info > (3, 0)):
argspec = inspect.getfullargspec(func)
else:
argspec = inspect.getargspec(func)
except:
raise TypeError("unable to determine parameter count")
return -1 if argspec.varargs else len(argspec.args)
def print_get_parameter_count(mod):
for x in dir(mod):
e = mod.__dict__.get(x)
if isinstance(e, types.BuiltinFunctionType):
print("{}.{} takes {} argument(s)".format(mod.__name__, e.__name__, get_parameter_count(e)))
import os
print_get_parameter_count(os)
输出:
os._exit takes 1 argument(s)
os.abort takes 0 argument(s)
os.access takes 2 argument(s)
os.chdir takes 1 argument(s)
os.chmod takes 2 argument(s)
os.close takes 1 argument(s)
...
这篇关于获取Python内置函数的parameter(arg)计数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!