【问题标题】:How can I find the number of arguments of a Python function?如何找到 Python 函数的参数数量?
【发布时间】:2010-10-25 06:41:21
【问题描述】:

如何找到 Python 函数的参数数量?我需要知道它有多少普通参数以及有多少命名参数。

例子:

def someMethod(self, arg1, kwarg1=None):
    pass

此方法有 2 个参数和 1 个命名参数。

【问题讨论】:

  • 这个问题是完全有根据的;如果不是(因为您总是可以阅读源代码),那么inspect 标准库模块就没有任何理由。
  • 很多语言都实现了至少一个不合理的特性。 inspect 模块还有很多其他功能,所以如果说整个模块中的一个特定功能是不合理的,这是不公平的。此外,很容易看出此功能如何使用不当。 (见stackoverflow.com/questions/741950)。也就是说,它是一个有用的特性,尤其是对于编写装饰器和其他对函数进行操作的函数。
  • @flow 你所说的“完全保证”是什么意思?

标签: python function


【解决方案1】:

截至Python 3.0,之前接受的答案是deprecated。您现在应该选择取代它的 Signature 类,而不是使用 inspect.getargspec

通过signature function 为函数创建签名很容易:

from inspect import signature

def someMethod(self, arg1, kwarg1=None):
    pass

sig = signature(someMethod)

现在,您可以通过string 快速查看其参数:

str(sig)  # returns: '(self, arg1, kwarg1=None)'

或者您也可以通过sig.parameters 获取属性名称到参数对象的映射。

params = sig.parameters 
print(params['kwarg1']) # prints: kwarg1=20

此外,您还可以在 sig.parameters 上调用 len 以查看此函数所需的参数数量:

print(len(params))  # 3

params 映射中的每个条目实际上是一个 Parameter object,它具有使您的生活更轻松的更多属性。例如,现在可以通过以下方式轻松获取参数并查看其默认值:

kwarg1 = params['kwarg1']
kwarg1.default # returns: None

parameters 中包含的其余对象也是如此。


对于 Python 2.x 用户,虽然 inspect.getargspec 已弃用,但该语言很快就会:-)。 Signature 类在 2.x 系列中不可用,也不会。所以你仍然需要使用inspect.getargspec

至于在 Python 2 和 3 之间转换,如果你的代码依赖于 Python 2 中的 getargspec 接口,而在 3 中切换到 signature 太难了,你确实有使用inspect.getfullargspec 的选项。它提供了与getargspec(单个可调用参数)类似的接口,以便获取函数的参数,同时处理getargspec 没有的一些其他情况:

from inspect import getfullargspec

def someMethod(self, arg1, kwarg1=None):
    pass

args = getfullargspec(someMethod)

getargspec 一样,getfullargspec 返回一个包含参数的NamedTuple

print(args)
FullArgSpec(args=['self', 'arg1', 'kwarg1'], varargs=None, varkw=None, defaults=(None,), kwonlyargs=[], kwonlydefaults=None, annotations={})

【讨论】:

  • 不客气@GeorgSchölly。我很惊讶像这样的一个流行问题提供的解决方案要么被弃用,要么被偷偷摸摸(偷看co_argcount 属性。)
  • getfullargspec在Python 2.x中没有实现,需要使用getargspec
  • getargspec 不适用于内置函数:getargspec(open) 提供 TypeError: <built-in function open> is not a Python function 一些想法请参阅 this answer...
  • 在上一个示例中,当您执行print(args) 时,您不会得到defaults=(None,),而是得到defaults=None
  • si 有一种方法可以获取装饰后装饰的函数的原始参数计数..?
【解决方案2】:
import inspect
inspect.getargspec(someMethod)

the inspect module

【讨论】:

【解决方案3】:
someMethod.func_code.co_argcount

或者,如果当前函数名称未确定:

import sys

sys._getframe().func_code.co_argcount

【讨论】:

  • @elyase,就这样吧:dir(someMethod) -> 'func_code';更进一步:dir(someMethod.func_code) -> 'co_argcount';您可以使用内置的dir() 来确定对象的可用方法。
  • @elyase 我也很好奇,所以我找到了这个docs.python.org/2/library/inspect.html#types-and-members
  • 支持 Python 3:six.get_function_code(someMethod).co_argcount
  • @noisecapella 不需要第三方模块,你可以简单地做some_method.__code__.co_argcount
  • 一般来说,您不应该在函数对象内部偷看这些东西。 co_argcount 在评估代码对象期间在内部使用。我想说的是,确实不能保证这些属性不会从一个版本更改为另一个版本。
【解决方案4】:

func.__code__.co_argcount 为您提供any 参数的数量 BEFORE *args

func.__kwdefaults__ 为您提供关键字参数 之后 *args

func.__code__.co_kwonlyargcount 等于 len(func.__kwdefaults__)

func.__defaults__ 为您提供 可选参数 的值,它们出现在 之前 *args

这是一个简单的例子:

>>> def a(b, c, d, e, f=1, g=3, h=None, *i, j=2, k=3, **L):
    pass

>>> a.__code__.co_argcount
7
>>> a.__defaults__
(1, 3, None)
>>> len(a.__defaults__)
3
>>> 
>>> 
>>> a.__kwdefaults__
{'j': 2, 'k': 3}
>>> len(a.__kwdefaults__)
2
>>> a.__code__.co_kwonlyargcount
2

【讨论】:

  • 感谢您的精彩说明!
【解决方案5】:

inspect.getargspec()

获取函数参数的名称和默认值。返回一个包含四件事的元组:(args、varargs、varkw、defaults)。 args 是参数名称的列表(它可能包含嵌套列表)。 varargs 和 varkw 是 * 和 ** 参数的名称或无。 defaults 是默认参数值的元组,如果没有默认参数,则为 None;如果这个元组有 n 个元素,它们对应于 args 中列出的最后 n 个元素。

在 2.6 版中更改:返回命名元组 ArgSpec(args, varargs, keywords, defaults)。

can-you-list-the-keyword-arguments-a-python-function-receives

【讨论】:

    【解决方案6】:

    除此之外,我还看到大多数时候 help() 函数确实有帮助

    例如,它给出了它所接受的参数的所有细节。

    help(<method>)
    

    给出以下内容

    method(self, **kwargs) method of apiclient.discovery.Resource instance
    Retrieves a report which is a collection of properties / statistics for a specific customer.
    
    Args:
      date: string, Represents the date in yyyy-mm-dd format for which the data is to be fetched. (required)
      pageToken: string, Token to specify next page.
      parameters: string, Represents the application name, parameter name pairs to fetch in csv as app_name1:param_name1, app_name2:param_name2.
    
    Returns:
      An object of the form:
    
        { # JSON template for a collection of usage reports.
        "nextPageToken": "A String", # Token for retrieving the next page
        "kind": "admin#reports#usageReports", # Th
    

    【讨论】:

    • 人们最好对帖子的问题发表评论,而不是只点击减号按钮。
    • help 函数只显示文档字符串所说的内容。您是否测试过它是否适用于问题中的函数定义?
    • @0xc0de - 你测试过吗?因为它确实有效。 help() 吐出的不仅仅是文档字符串 - 即使在未记录的代码上,它仍然会打印出 argspec 并告诉您代码的定义位置。发布原始问题的人不清楚他们是否需要一个机器友好的答案或人类友好的答案。如果它只需要对人类友好,help() 就足够了。
    • @ArtOfWarfare 一点也不,因为现在你必须解析help() 返回的任何内容,并尝试找到argskwargs
    【解决方案7】:

    对于想要在 Python 2 和 Python 3.6+ 之间以可移植方式执行此操作的人来说是个好消息:使用 inspect.getfullargspec() 方法。它适用于 Python 2.x 和 3.6+

    正如 Jim Fasarakis Hilliard 和其他人所指出的,过去是这样的:
    1. 在 Python 2.x 中:使用inspect.getargspec()
    2. 在 Python 3.x 中:使用签名,因为 getargspec()getfullargspec() 已弃用。

    然而,从 Python 3.6 开始(应大众需求?),事情已经变得更好了:

    来自 Python 3 documentation page

    inspect.getfullargspec(func)

    在 3.6 版中更改:此方法以前在 Python 3.5 中被记录为不推荐使用,而支持 signature(),但为了恢复一个明确支持的标准接口,该决定已被撤销。源 Python 2/3 代码从旧版 getargspec() API 迁移出来。

    【讨论】:

      【解决方案8】:

      正如其他答案所暗示的,只要被查询的东西实际上是一个函数,getargspec 就可以很好地工作。它不适用于内置函数,例如openlen等,在这种情况下会抛出异常:

      TypeError: <built-in function open> is not a Python function
      

      以下函数(受this answer 启发)演示了一种解决方法。它返回 f 期望的 args 数量:

      from inspect import isfunction, getargspec
      def num_args(f):
        if isfunction(f):
          return len(getargspec(f).args)
        else:
          spec = f.__doc__.split('\n')[0]
          args = spec[spec.find('(')+1:spec.find(')')]
          return args.count(',')+1 if args else 0
      

      这个想法是从__doc__ 字符串中解析出函数规范。显然,这依赖于所述字符串的格式,因此几乎没有鲁棒性!

      【讨论】:

        【解决方案9】:

        inspect.getargspec() 以满足您的需求

        from inspect import getargspec
        
        def func(a, b):
            pass
        print len(getargspec(func).args)
        

        【讨论】:

        • 欢迎来到 Stack Overflow!请不要只用源代码回答。尝试对您的解决方案如何工作提供一个很好的描述。请参阅:How do I write a good answer?。谢谢
        【解决方案10】:

        你得到参数的数量(用你的函数名替换“function”):

        function.__code__.co_argcount ## 2
        
        

        以及参数的名称:

        function.__code__.co_varnames ## ('a', 'b')
        

        【讨论】:

          【解决方案11】:

          在:

          import inspect 
          
          class X:
              def xyz(self, a, b, c): 
                  return 
          
          print(len(inspect.getfullargspec(X.xyz).args))
          

          输出:

          4


          注意:如果 xyz 不在类 X 中并且没有“self”而只有“a,b,c”,那么它会打印 3。

          对于低于 3.5 的 python,您可能希望在上面的代码中将 inspect.getfullargspec 替换为 inspect.getargspec

          【讨论】:

            【解决方案12】:

            Dimitris Fasarakis Hilliard 接受的答案建议以字符串格式获取参数,但我认为在解析此字符串时可能会出错,因此我直接使用检查模块创建了一个参数列表

            import inspect
            def my_function(a,b,c):
                #some code
                pass
            
            result=list(inspect.signature(my_function).parameters.keys())
            print(result)
            ['a','b','c']
            

            【讨论】:

              【解决方案13】:

              假设您可能正在处理基于类的methods 或只是functions,您可以执行以下操作。

              如果输入是类方法,这将自动减去一个输入(因此包括self)。

              import types
              def get_arg_count(fn):
                  extra_method_input_count=1 if isinstance(fn, types.MethodType) else 0
                  return fn.__code__.co_argcount-extra_method_input_count
              

              然后你可以根据需要申请函数或方法:

              def fn1(a, b, c):
                  return None
              
              class cl1:
                  def fn2(self, a, b, c):
                      return None
              
              print(get_arg_count(fn1)) #=> 3
              print(get_arg_count(cl1().fn2)) #=> 3
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-06-17
                • 1970-01-01
                • 2011-07-13
                • 1970-01-01
                相关资源
                最近更新 更多