2010-07-18 46 views
3

我需要以编程方式获取函数需要的参数的数量。在模块中声明的函数,这是微不足道的:如何获取Python中内置函数的参数个数?

myfunc.func_code.co_argcount 

但是内置功能没有func_code属性。有没有另一种方法来做到这一点?否则,我不能使用内置插件,而必须在我的代码中重新编写它们。

[添加]感谢您的回复,希望他们会有用。我用Pypy来代替。

+0

我张贴在这里的另一种方法:https://stackoverflow.com/questions/48567935/get-parameter-count-of-builtin-functions-in-python – HelloWorld 2018-02-01 18:28:14

回答

2

看看下面从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 
1

我不相信这种类型的内省是可能的内置函数或任何C扩展功能。

A similar question已经在这里提出,Alex的答案建议解析函数的文档字符串以确定参数的数量。

0

这是不可能的。 C函数不会以编程方式公开它们的参数签名。

+0

这是可能的。我在这里发布了一个解决方案:https://stackoverflow.com/questions/48567935/get-parameterarg-count-of-builtin-functions-in-python – HelloWorld 2018-02-02 04:39:59

0

有趣的解决方案,希望它也能帮助别人。

我采取了另一种方式:我听说Pypy是python主要实现的。所以我尝试PyPy(JIT版本),它的工作。我还没有找到“硬编码”功能。无法找到如何将其安装在/ usr中,但它从解压缩的文件夹中运行。

1

也许是Alex给出的解析函数的一个更强大的替代方法,但是这仍然无法给出适当的arg规范,因为并不是所有的文档都完全代表它们函数的签名。

一个很好的例子是dict.get在ARGS规范应该是(k, d=None),但我已经定义的函数将返回(k, d),因为没有默认的形式d=None给予d。在文档字符串"f(a[, b, c])"中,参数bc是默认值,但没有真正的方法来解析它们,因为没有直接指定值,在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]) 
相关问题