理解Python中的函数参数

时间:2016-06-19 17:05:05

标签: python python-decorators args kwargs

我试图了解以下有关处理函数及其参数的内容:

def print_my_arg(func, *args, **kwargs):
    func(*args, **kwargs)
    if 'my_arg' in kwargs: 
        print('  my_arg = {}'.format(kwargs['my_arg']))

def foo(call_no, my_arg='Default Value'):
    print('call_no = {}'.format(call_no) )

print_my_arg(foo, 0, my_arg='My Value 1')
print_my_arg(foo, 1, 'My Value 2')
print_my_arg(foo, 2)

输出:

call_no = 0
  my_arg = My Value 1
call_no = 1 # I'd like to see 'My Value 2' here
call_no = 2 # I'd like to see 'Default Value' here

显然人们可以通过上面显示的任何一种方式自由调用函数,这让我想知道:为什么my_arg无法转到kwargs?是不是有一种统一的方式来按名称(而不是按位置)访问参数,这不依赖于调用函数的方式?

请注意:

  1. 我对print_my_args(func, call_no, my_arg)不感兴趣,因为我正在谈论我事先并不知道func签名的情况我想知道某个特定参数是否存在(按名称)。

  2. 显然这与装饰者有关,但我以更简单的方式编写了这个例子(或者我希望如此)。

  3. 修改

    非常感谢inspect.signature的答案。使用它,我的print_my_arg()新版本是:

    from inspect import signature
    
    def print_my_arg ( func, *args, **kwargs ):
      func ( *args, **kwargs )
      sig = signature ( func )
      if 'my_arg' not in sig.parameters: return
    
      binding = sig.bind ( *args, **kwargs )
      binding.apply_defaults ()
    
      print ( "  my_arg = {}".format ( binding.arguments [ 'my_arg' ] ) )
    

1 个答案:

答案 0 :(得分:3)

  

是否有统一的方式来按名称访问参数(而不是   位置),它不依赖于调用函数的方式?

inspect signature

>>> import inspect
>>> sig = inspect.signature(foo)
>>> print(sig)
(call_no, my_arg='Default Value')
>>> args = sig.bind(1, "my_value")
>>> args.arguments["my_arg"]
'my_value'

请注意,尝试将签名绑定到无效调用将引发在调用具有无效参数的函数时引发的类似/相同的TypeError。除非您致电args.arguments

,否则args.apply_defaults()中不会出现使用默认值的参数

另请注意,仅关键字参数将位于args.kwargs字典而非args.arguments

import inspect

def bar(a,*, b=None):
    pass

sig = inspect.signature(bar)

binding = sig.bind(1, b=5)

assert "a" in binding.arguments
assert "b" in binding.kwargs