解压缩和*运算符

Lea*_*Xue 31 python unzip

python docs将此代码作为zip的反向操作:

>>> x2, y2 = zip(*zipped)
Run Code Online (Sandbox Code Playgroud)

特别是"zip()与*运算符一起使用可以解压缩列表".有人可以向我解释*运算符在这种情况下是如何工作的吗?据我所知,*是一个二元运算符,可用于乘法或浅拷贝......这两者似乎都不是这种情况.

Bla*_*air 61

虽然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
Run Code Online (Sandbox Code Playgroud)

我们可以创建一个列表(或那个元组)来保存它们,然后告诉Python 解包该列表并使用其内容作为函数的参数,而不是直接指定参数:

>>> arguments = [42, 'insert value here', 3.14]
>>> do_something(*arguments)
arg1: 42
arg2: insert value here
arg3: 3.14
Run Code Online (Sandbox Code Playgroud)

如果您没有足够的参数(或太多),则表现正常:

>>> 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)
Run Code Online (Sandbox Code Playgroud)

在定义函数时,可以使用相同的构造来接受任意数量的位置参数.它们作为元组赋予您的功能:

>>> 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
Run Code Online (Sandbox Code Playgroud)

当然,您可以结合使用这两种技术:

>>> show_args(*arguments)
Argument 0: 42
Argument 1: insert value here
Run Code Online (Sandbox Code Playgroud)

您可以使用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
Run Code Online (Sandbox Code Playgroud)

当然,您可以通过字典传递关键字参数:

>>> values = {'name': 'John', 'age': 17}
>>> show_kwargs(**values)
age = 17
name = John
Run Code Online (Sandbox Code Playgroud)

混合两者是完全可以接受的,你总是可以为函数提供必需的参数和可选的额外参数:

>>> 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>}
Run Code Online (Sandbox Code Playgroud)

如果您正在使用可选的关键字参数并且您希望拥有默认值,请记住您正在处理字典,因此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>
Run Code Online (Sandbox Code Playgroud)


ham*_*mar 22

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)]
Run Code Online (Sandbox Code Playgroud)


Phi*_*ham 22

当像这样使用时,*(星号,在某些圆圈中也称为"splat"运算符)是从列表中解压缩参数的信号.有关示例,请参阅http://docs.python.org/tutorial/controlflow.html#unpacking-argument-lists以获得更完整的定义.


cgl*_*cet 6

一旦你真正理解了它的作用,这实际上非常简单zip()

zip函数接受多个参数(全部为可迭代类型),并根据这些可迭代项各自的位置对项进行配对。

例如,假设我们有两个参数ranked_athletes, rewards传递给zip,函数调用zip(ranked_athletes, rewards) 将:

  • 将排名第一(位置 i=0)的运动员与第一/最佳奖励(位置 i=0)配对
  • 它将移动下一个元素,i=1
  • 将第二名运动员与其奖励配对,第二名运动员来自reward
  • ...

这将重复进行,直到不再有运动员或奖励为止。例如,如果我们在 2016 年奥运会上参加 100m 比赛,zip我们获得的奖励是:

ranked_athletes = ["Usain Bolt", "Justin Gatlin", "Andre De Grasse", "Yohan Blake"]
rewards = ["Gold medal", "Silver medal", "Bronze medal"]
zip(ranked_athletes, rewards)
Run Code Online (Sandbox Code Playgroud)

将返回以下元组(对)的迭代器:

('Usain Bolt', 'Gold medal')
('Justin Gatlin', 'Silver medal')
('Andre De Grasse', 'Bronze medal')
Run Code Online (Sandbox Code Playgroud)

请注意Yohan Blake如何没有奖励(因为列表中没有更多奖励rewards)。

*运算符允许解包列表,例如列表[1, 2]解包为1, 2. 它基本上将一个对象转换为多个对象(与列表的大小一样多)。您可以在此处阅读有关此运算符的更多信息。

因此,如果我们将这两者结合起来,zip(*x)实际上意味着:获取这个对象列表,将其解压缩为许多对象,并根据所有这些对象的索引对项目进行配对。仅当对象是可迭代的(例如列表)时才有意义,否则索引的概念实际上没有意义。

如果您一步步执行,结果如下:

('Usain Bolt', 'Gold medal')
('Justin Gatlin', 'Silver medal')
('Andre De Grasse', 'Bronze medal')
Run Code Online (Sandbox Code Playgroud)

请注意,在这种情况下,如果我们调用,print(list(zip(x)))我们只会将x(这是 2 个列表)中的项目与任何内容配对(因为没有其他可迭代对象可以将它们配对):

[  ([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']
Run Code Online (Sandbox Code Playgroud)

理解zip工作原理的另一种好方法是实现您自己的版本,下面的方法或多或少会执行与以下相同的工作,但zip仅限于两个列表(而不是许多可迭代对象)的情况:

>>> 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')]
Run Code Online (Sandbox Code Playgroud)

请注意,我没有调用print(list(zip_two_lists(*x)))它,因为与实际函数不同,这个函数zip不是生成器(构造迭代器的函数),而是我们在内存中创建一个列表。因此这个函数不是那么好,你可以在Python的文档中找到一个更接近真实值的函数zip。阅读本文档中的这些等效代码通常是一个好主意,这是清楚地理解函数功能的好方法。