解压和 * 运算符
Python的文档中给出了这个代码,作为zip的反向操作:
>>> x2, y2 = zip(*zipped)
特别地,
zip()和*运算符一起使用,可以用来解压一个列表。
有人能给我解释一下在这种情况下*运算符是怎么工作的吗?我理解的情况是,*是一个二元运算符,可以用来做乘法或者浅拷贝……但在这里似乎都不是这样。
5 个回答
25
zip(*zipped)
的意思是“把 zipped
中的每个元素作为参数传给 zip
”。zip
有点像转置一个矩阵,也就是说,如果你再做一次,就会回到最初的状态。
>>> a = [(1, 2, 3), (4, 5, 6)]
>>> b = zip(*a)
>>> b
[(1, 4), (2, 5), (3, 6)]
>>> zip(*b)
[(1, 2, 3), (4, 5, 6)]
62
虽然hammar的回答解释了在使用zip()
函数时如何进行反转,但我们可以更广泛地理解参数解包。假设我们有一个简单的函数,它需要一些参数:
>>> def do_something(arg1, arg2, arg3):
... print 'arg1: %s' % arg1
... print 'arg2: %s' % arg2
... print 'arg3: %s' % arg3
...
>>> do_something(1, 2, 3)
arg1: 1
arg2: 2
arg3: 3
我们可以不直接写出这些参数,而是先创建一个列表(或者元组),把参数放在里面,然后告诉Python去解包这个列表,把里面的内容当作参数传给函数:
>>> arguments = [42, 'insert value here', 3.14]
>>> do_something(*arguments)
arg1: 42
arg2: insert value here
arg3: 3.14
如果你传的参数不够(或者太多),这依然会正常工作:
>>> arguments = [42, 'insert value here']
>>> do_something(*arguments)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/home/blair/<ipython console> in <module>()
TypeError: do_something() takes exactly 3 arguments (2 given)
在定义函数时,你也可以使用相同的方法来接受任意数量的位置参数。这些参数会以元组的形式传给你的函数:
>>> def show_args(*args):
... for index, value in enumerate(args):
... print 'Argument %d: %s' % (index, value)
...
>>> show_args(1, 2, 3)
Argument 0: 1
Argument 1: 2
Argument 2: 3
当然,你也可以把这两种方法结合起来使用:
>>> show_args(*arguments)
Argument 0: 42
Argument 1: insert value here
对于关键字参数,你可以用两个星号(**
)和一个字典来做类似的事情:
>>> def show_kwargs(**kwargs):
... for arg, value in kwargs.items():
... print '%s = %s' % (arg, value)
...
>>> show_kwargs(age=24, name='Blair')
age = 24
name = Blair
当然,你也可以通过字典传递关键字参数:
>>> values = {'name': 'John', 'age': 17}
>>> show_kwargs(**values)
age = 17
name = John
将这两种方法混合使用是完全可以的,你可以在函数中有必需的参数和可选的额外参数:
>>> def mixed(required_arg, *args, **kwargs):
... print 'Required: %s' % required_arg
... if args:
... print 'Extra positional arguments: %s' % str(args)
... if kwargs:
... print 'Extra keyword arguments: %s' % kwargs
...
>>> mixed(1)
Required: 1
>>> mixed(1, 2, 3)
Required: 1
Extra positional arguments: (2, 3)
>>> mixed(1, 2, 3, test=True)
Required: 1
Extra positional arguments: (2, 3)
Extra keyword arguments: {'test': True}
>>> args = (2, 3, 4)
>>> kwargs = {'test': True, 'func': min}
>>> mixed(*args, **kwargs)
Required: 2
Extra positional arguments: (3, 4)
Extra keyword arguments: {'test': True, 'func': <built-in function min>}
如果你要接受可选的关键字参数,并且想要设置默认值,记得你是在处理一个字典,因此可以使用它的get()
方法,并设置一个默认值,以防这个键不存在:
>>> def take_keywords(**kwargs):
... print 'Test mode: %s' % kwargs.get('test', False)
... print 'Combining function: %s' % kwargs.get('func', all)
...
>>> take_keywords()
Test mode: False
Combining function: <built-in function all>
>>> take_keywords(func=any)
Test mode: False
Combining function: <built-in function any>
23
当像这样使用时,*(星号,有时候也被称为“展开运算符”)是用来从一个列表中提取参数的信号。想要更详细的定义和例子,可以查看这个链接:http://docs.python.org/tutorial/controlflow.html#unpacking-argument-lists。