我需要以編程方式獲取函數需要的參數的數量。在模塊中聲明的函數,這是微不足道的:如何獲取Python中內置函數的參數個數?
myfunc.func_code.co_argcount
但是內置功能沒有func_code
屬性。有沒有另一種方法來做到這一點?否則,我不能使用內置插件,而必須在我的代碼中重新編寫它們。
[添加]感謝您的回覆,希望他們會有用。我用Pypy來代替。
我需要以編程方式獲取函數需要的參數的數量。在模塊中聲明的函數,這是微不足道的:如何獲取Python中內置函數的參數個數?
myfunc.func_code.co_argcount
但是內置功能沒有func_code
屬性。有沒有另一種方法來做到這一點?否則,我不能使用內置插件,而必須在我的代碼中重新編寫它們。
[添加]感謝您的回覆,希望他們會有用。我用Pypy來代替。
看看下面從here複製的功能。這可能是你能做的最好的。請注意有關inspect.getargspec
的意見。
def describe_builtin(obj):
""" Describe a builtin function """
wi('+Built-in Function: %s' % obj.__name__)
# Built-in functions cannot be inspected by
# inspect.getargspec. We have to try and parse
# the __doc__ attribute of the function.
docstr = obj.__doc__
args = ''
if docstr:
items = docstr.split('\n')
if items:
func_descr = items[0]
s = func_descr.replace(obj.__name__,'')
idx1 = s.find('(')
idx2 = s.find(')',idx1)
if idx1 != -1 and idx2 != -1 and (idx2>idx1+1):
args = s[idx1+1:idx2]
wi('\t-Method Arguments:', args)
if args=='':
wi('\t-Method Arguments: None')
print
我不相信這種類型的內省是可能的內置函數或任何C擴展功能。
A similar question已經在這裏提出,Alex的答案建議解析函數的文檔字符串以確定參數的數量。
這是不可能的。 C函數不會以編程方式公開它們的參數簽名。
這是可能的。我在這裏發佈了一個解決方案:https://stackoverflow.com/questions/48567935/get-parameterarg-count-of-builtin-functions-in-python – HelloWorld 2018-02-02 04:39:59
有趣的解決方案,希望它也能幫助別人。
我採取了另一種方式:我聽說Pypy是python主要實現的。所以我嘗試PyPy(JIT版本),它的工作。我還沒有找到「硬編碼」功能。無法找到如何將其安裝在/ usr中,但它從解壓縮的文件夾中運行。
也許是Alex給出的解析函數的一個更強大的替代方法,但是這仍然無法給出適當的arg規範,因爲並不是所有的文檔都完全代表它們函數的簽名。
一個很好的例子是dict.get
在ARGS規範應該是(k, d=None)
,但我已經定義的函數將返回(k, d)
,因爲沒有默認的形式d=None
給予d
。在文檔字符串"f(a[, b, c])"
中,參數b
和c
是默認值,但沒有真正的方法來解析它們,因爲沒有直接指定值,在dict.get
的情況下,行爲將在後面描述,而不是在簽名表示中。
儘管如此,光明正大的是,它捕捉了所有參數,只是默認值不可靠。
import re
import inspect
def describe_function(function):
"""Return a function's argspec using its docstring
If usages discovered in the docstring conflict, or default
values could not be resolved, a generic argspec of *arg
and **kwargs is returned instead."""
s = function.__doc__
if s is not None:
usages = []
p = r'([\w\d]*[^\(])\(?([^\)]*)'
for func, usage in re.findall(p, s):
if func == function.__name__:
usages.append(usage)
longest = max(usages, key=lambda s: len(s))
usages.remove(longest)
for u in usages:
if u not in longest:
# the given usages weren't subsets of a larger usage.
return inspect.ArgSpec([], 'args', 'kwargs', None)
else:
args = []
varargs = None
keywords = None
defaults = []
matchedargs = re.findall(r'(?[^\[,\]]*) ?,? ?', longest)
for a in [a for a in matchedargs if len(a)!=0]:
if '=' in a:
name, default = a.split('=')
args.append(name)
p = re.compile(r"<\w* '(.*)'>")
m = p.match(default)
try:
if m:
d = m.groups()[0]
# if the default is a class
default = import_item(d)
else:
defaults.append(eval(default))
except:
# couldn't resolve a default value
return inspect.ArgSpec([], 'args', 'kwargs', None)
elif '**' in a:
keywords = a.replace('**', '')
elif '*' in a:
varargs = a.replace('*', '')
else:
args.append(a)
return inspect.ArgSpec(args, varargs, keywords, defaults)
# taken from traitlet.utils.importstring
def import_item(name):
"""Import and return ``bar`` given the string ``foo.bar``.
Calling ``bar = import_item("foo.bar")`` is the functional equivalent of
executing the code ``from foo import bar``.
Parameters
----------
name : string
The fully qualified name of the module/package being imported.
Returns
-------
mod : module object
The module that was imported.
"""
if not isinstance(name, string_types):
raise TypeError("import_item accepts strings, not '%s'." % type(name))
name = cast_bytes_py2(name)
parts = name.rsplit('.', 1)
if len(parts) == 2:
# called with 'foo.bar....'
package, obj = parts
module = __import__(package, fromlist=[obj])
try:
pak = getattr(module, obj)
except AttributeError:
raise ImportError('No module named %s' % obj)
return pak
else:
# called with un-dotted string
return __import__(parts[0])
我張貼在這裏的另一種方法:https://stackoverflow.com/questions/48567935/get-parameter-count-of-builtin-functions-in-python – HelloWorld 2018-02-01 18:28:14