[Python学习笔记-004] 可变参数*args和**kwargs

在Python中,可变参数的传递使用*args**kwargs来实现,其中:

  • *args表示任意个位置参数(positional argument),被表示为一个只读的数组(tuple);
  • **kwargs表示任意个关键字参数(keyword argument),被表示为一个字典(dict)。

例如:

>>> def foo(*args, **kwargs):
...     print("*args:		", args)
...     print("**kwargs:	", kwargs)
...
>>>
>>> foo()
*args:           ()
**kwargs:        {}
>>> foo(1)
*args:           (1,)
**kwargs:        {}
>>> foo(1, 2)
*args:           (1, 2)
**kwargs:        {}
>>>
>>> foo(a=1, b=2)
*args:           ()
**kwargs:        {'a': 1, 'b': 2}
>>>
>>> foo(1, 2, a=1, b=2, c=3)
*args:           (1, 2)
**kwargs:        {'a': 1, 'b': 2, 'c': 3}
>>>
>>> foo(1, 2, [3, 4, 5], a=1, b=2, c={'A':1, 'B':2, 'C':3})
*args:           (1, 2, [3, 4, 5])
**kwargs:        {'a': 1, 'b': 2, 'c': {'A': 1, 'B': 2, 'C': 3}}
>>>
>>> foo(1, a=1, 2, b=2, 3, c=3)
  File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
>>>

注意: 位置参数(*args)必须在关键字参数(**kwargs)的前面。

另外,*args和**kwargs都是可以无限次地向下传递的(这一点类似Bash里的"$@"),例如:

  • foo_args.py
 1 #!/usr/bin/python
 2 
 3 from __future__ import print_function
 4 import sys
 5 
 6 def l2_foo(*args):
 7     print(">>L2:		*args =", args, "
")
 8 
 9 def l1_foo(head, *args):
10     print(" >L1: head =", head, "	*args =", args)
11     l2_foo(*args)
12 
13 def main(argc, argv):
14     l1_foo(1)
15     l1_foo(1, 2)
16     l1_foo(1, 2, 3)
17 
18     return 0
19 
20 if __name__ == '__main__':
21     argv = sys.argv
22     argc = len(argv)
23     sys.exit(main(argc, argv))

注意L6, L9 和 L11:

 6  def l2_foo(*args):
..
 9  def l1_foo(head, *args):
..
11      l2_foo(*args)
  • 运行foo_args.py
$ ./foo_args.py 
 >L1: head = 1  *args = ()
>>L2:           *args = () 

 >L1: head = 1  *args = (2,)
>>L2:           *args = (2,) 

 >L1: head = 1  *args = (2, 3)
>>L2:           *args = (2, 3) 

最后,给出一个使用*args的更有工程意义的例子:

  • foo.py
 1 #!/usr/bin/python
 2 from __future__ import print_function
 3 import sys
 4 
 5 class Foo(object):
 6     def __init__(self, name, oid):
 7         self.name = name
 8         self.oid = oid
 9 
10     def get_name(self):
11         return self.name
12 
13     def set_name(self, name):
14         self.name = name
15 
16     def get_info(self):
17         return "name = %s, oid = %d" % (self.name, self.oid)
18 
19     def set_info(self, name, oid):
20         self.name = name
21         self.oid = oid
22 
23 class Bar(object):
24     def __init__(self, name, oid):
25         self.foo = Foo(name, oid)
26 
27     def __op_foo(self, method, *args):
28         func = getattr(self.foo, method)
29         try:
30             prop = func(*args)
31             return prop
32         except Exception as e:
33             print(e)
34 
35     def foo_set_name(self, name):
36         return self.__op_foo('set_name', name)
37 
38     def foo_get_name(self):
39         return self.__op_foo('get_name')
40 
41     def foo_set_info(self, name, oid):
42         return self.__op_foo('set_info', name, oid)
43 
44     def foo_get_info(self):
45         return self.__op_foo('get_info')
46 
47     def get_oid(self):
48         return self.foo.oid  # XXX: Ugly but simple for demo
49 
50 def foo_arg0():
51     b = Bar('Jack', 12345)
52     s = b.foo_get_name()
53     print("foo_arg0: name = %s, oid = %d" % (s, b.get_oid()))
54 
55 def foo_arg1():
56     b = Bar('Jack', 12345)
57     o = b.foo_set_name('Lynn')
58     print("foo_arg1: return", o)
59     s = b.foo_get_name()
60     print("foo_arg1: name = %s, oid = %d" % (s, b.get_oid()))
61 
62 def foo_arg2():
63     b = Bar('Jack', 12345)
64     o = b.foo_set_info('Mary', 54321)
65     print("foo_arg2: return", o)
66     s = b.foo_get_info()
67     print("foo_arg2: %s" % s)
68 
69 def main(argc, argv):
70     if argc != 2:
71         sys.stderr.write("Usage: %s <func ID>
" % argv[0])
72         return 1
73 
74     func_id = int(argv[1])
75     exec('foo_arg%d()' % func_id)
76 
77     return 0
78 
79 if __name__ == '__main__':
80     argv = sys.argv
81     argc = len(argv)
82     sys.exit(main(argc, argv))
  • 运行foo.py
$ ./foo.py 0
foo_arg0: name = Jack, oid = 12345
$ ./foo.py 1
foo_arg1: return None
foo_arg1: name = Lynn, oid = 12345
$ ./foo.py 2
foo_arg2: return None
foo_arg2: name = Mary, oid = 54321

小结:在函数的参数列表中,零个*表示普通的位置参数, 一个*表示元组(tuple), 两个*表示字典(dict)。

1 '*' * 0:   arg : regular arg
2 '*' * 1:  *args: tuple (i.e. readonly list)
3 '*' * 2: **args: dict
原文地址:https://www.cnblogs.com/idorax/p/9486756.html