代码之家  ›  专栏  ›  技术社区  ›  culebrón

如何获取Python中内置函数的参数数?

  •  3
  • culebrón  · 技术社区  · 14 年前

    我需要以编程方式获取函数所需的参数数。对于在模块中声明的函数,这很简单:

    myfunc.func_code.co_argcount
    

    但是内置函数没有 func_code

    [补充]感谢您的回复,希望对您有所帮助。我用Pypy代替了。

    5 回复  |  直到 14 年前
        1
  •  2
  •   ars    14 年前

    请看下面的函数 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
    
        2
  •  1
  •   Community CDub    8 年前
        3
  •  1
  •   rmorshea    9 年前

    一个很好的例子是 dict.get args规范应该在哪里 (k, d=None) ,但我定义的函数将返回 (k, d) ,因为没有为 d d=None "f(a[, b, c])" 阿格斯 b c

    不过,从好的方面来看,这抓住了所有的论点,只是默认值不可靠。

    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])
    
        4
  •  0
  •   Alex Gaynor    14 年前

        5
  •  0
  •   culebrón    14 年前

    有趣的解决办法,阿瑟。希望它也能帮助别人。

    我走了另一条路:我听说Pypy主要是python本身实现的。所以我试过了 PyPy (JIT版本)并且它工作了。我还没有找到“硬编码”函数。找不到如何在/usr中安装它,但它可以在解包的文件夹中工作。