在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