python docs将此代码作为zip的反向操作:
>>> x2, y2 = zip(*zipped)
特别是“zip()与*运算符一起使用可以解压缩列表”。有人可以向我解释*运算符在这种情况下是如何工作的吗?据我所知,*是一个二元运算符,可以用于乘法或浅拷贝......这两种情况似乎都不是这样。
答案 0 :(得分:59)
尽管hammar's answer解释了在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
您可以使用double asterix(**
)和字典对关键字参数执行类似的操作:
>>> 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>
答案 1 :(得分:20)
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)]
答案 2 :(得分:20)
当像这样使用时,*(星号,在某些圆圈中也称为“splat”运算符)是从列表中解包参数的信号。有关示例的更完整定义,请参阅http://docs.python.org/tutorial/controlflow.html#unpacking-argument-lists。
答案 3 :(得分:0)
一旦您真正了解了zip()
的作用,那实际上就非常简单。
zip
函数接受几个参数(所有可迭代类型),并根据它们各自的位置配对这些可迭代对象中的项。
例如,假设我们有两个参数ranked_athletes, rewards
传递给zip
,则函数调用zip(ranked_athletes, rewards
)将:
reward
中的第二名。这将重复进行,直到不再有运动员或奖励为止。例如,如果我们在2016年奥运会上获得1亿,并zip
所获得的奖励,则:
ranked_athletes = ["Usain Bolt", "Justin Gatlin", "Andre De Grasse", "Yohan Blake"]
rewards = ["Gold medal", "Silver medal", "Bronze medal"]
zip(ranked_athletes, rewards)
将在以下元组(对)上返回迭代器:
('Usain Bolt', 'Gold medal')
('Justin Gatlin', 'Silver medal')
('Andre De Grasse', 'Bronze medal')
请注意 Yohan Blake 没有奖励。
现在,*
运算符更加简单,如果您有列表[1, 2]
,则将其解压缩到1, 2
。它基本上将一个对象转换成许多对象(与列表大小一样多)。
因此,如果我们将两者结合起来,zip(*x)
实际上意味着: 获取此对象列表,将其解压缩为许多对象,并根据它们的索引将所有这些对象中的项目配对 。仅当对象是可迭代的(例如,例如列表)时才有意义,否则 index 的概念就没有任何意义。
如果逐步执行,将显示以下内容:
>>> print(x) # x is a list of lists
[[1, 2, 3], ['a', 'b', 'c', 'd']]
>>> print(*x) # unpack x
[1, 2, 3] ['a', 'b', 'c', 'd']
>>> print(list(zip(*x))) # And pair items from the resulting lists
[(1, 'a'), (2, 'b'), (3, 'c')]
请注意,在这种情况下,如果我们调用print(list(zip(x)))
,我们将仅将x
(属于2个列表)中的项目配对而没有任何内容(因为没有其他可迭代的配对方法):< / p>
[ ([1, 2, 3], ), (['a', 'b', 'c', 'd'], )]
^ ^
[1, 2, 3] is paired with nothing |
|
same for the 2nd item from x: ['a', 'b', 'c', 'd']
了解zip
的工作方式的另一种好方法是实现自己的版本,这与zip
或多或少会起到相同的作用,但仅限于两个列表(而不是两个)许多可迭代项):
def zip_two_lists(A, B):
shortest_list_size = min(len(A), len(B))
# We create empty pairs
pairs = [tuple() for _ in range(shortest_list_size)]
# And fill them with items from each iterable
# according to their the items index:
for index in range(shortest_list_size):
pairs[index] = (A[index], B[index])
return pairs
print(zip_two_lists(*x))
# Outputs: [(1, 'a'), (2, 'b'), (3, 'c')]
请注意,我之所以没有调用print(list(zip_two_lists(*x)))
是因为与真正的zip
不同,该函数不是生成器(构造迭代器的函数),而是在内存中创建一个列表。因此,此功能并不理想,您可以找到更好的approximation to the real zip
in Python's documentation。阅读本文档中的所有代码等效项通常是一个好主意,这是一种理解函数做什么而没有任何歧义的好方法。
答案 4 :(得分:-2)
我建议在使用izip_longest完成zip时解压缩列表的列表:
>>> a =[2,3,4,5,6]
>>> b = [5,4,3,2]
>>> c=[1,0]]
>>>[list([val for val in k if val != None]) for k in
zip(*itertools.izip_longest(a,b,c))]
因为izip_longest为最长的列表追加无,所以我事先删除了None。我回到原来的a,b,c
[[2, 3, 4, 5, 6], [5, 4, 3, 2], [1, 0]]