简体   繁体   English

理解 *x ,= lst

[英]Understanding *x ,= lst

I'm going through some old code trying to understand what it does, and I came across this odd statement:我正在查看一些旧代码,试图了解它的作用,但我遇到了这个奇怪的声明:

*x ,= p

p is a list in this context. p是此上下文中的列表。 I've been trying to figure out what this statement does.我一直在试图弄清楚这个声明的作用。 As far as I can tell, it just sets x to the value of p .据我所知,它只是将x设置为p的值。 For example:例如:

p = [1,2]
*x ,= p    
print(x)

Just gives只是给

[1, 2]

So is this any different than x = p ?那么这与x = p什么不同吗? Any idea what this syntax is doing?知道这个语法在做什么吗?

*x ,= p is basically an obfuscated version of x = list(p) using extended iterable unpacking . *x ,= p基本上是x = list(p)使用扩展迭代解包的混淆版本。 The comma after x is required to make the assignment target a tuple (it could also be a list though). x后面的逗号需要使分配目标成为元组(尽管它也可以是列表)。

*x, = p is different from x = p because the former creates a copy of p (ie a new list) while the latter creates a reference to the original list. *x, = p从不同的x = p ,因为前者产生的副本p (即一个新的列表),而后者产生的原始列表的引用 To illustrate:为了显示:

>>> p = [1, 2]
>>> *x, = p 
>>> x == p
True
>>> x is p
False
>>> x = p
>>> x == p
True
>>> x is p
True

It's a feature that was introduced in Python 3.0 ( PEP 3132 ).这是 Python 3.0 ( PEP 3132 ) 中引入的一项功能。 In Python 2, you could do something like this:在 Python 2 中,您可以执行以下操作:

>>> p = [1, 2, 3]
>>> q, r, s = p
>>> q
1
>>> r
2
>>> s
3

Python 3 extended this so that one variable could hold multiple values: Python 3 对此进行了扩展,以便一个变量可以保存多个值:

>>> p = [1, 2, 3]
>>> q, *r = p
>>> q
1
>>> r
[2, 3]

This, therefore, is what is being used here.因此,这就是这里使用的内容。 Instead of two variables to hold three values, however, it is just one variable that takes each value in the list.然而,它不是两个变量来保存三个值,而是一个变量来获取列表中的每个值。 This is different from x = p because x = p just means that x is another name for p .这与x = p不同,因为x = p仅表示xp另一个名称。 In this case, however, it is a new list that just happens to have the same values in it.然而,在这种情况下,它是一个刚好在其中具有相同值的新列表。 (You may be interested in "Least Astonishment" and the Mutable Default Argument ) (你可能对“Least Astonishment”和“Mutable Default Argument”感兴趣)

Two other common ways of producing this effect are:产生这种效果的另外两种常见方式是:

>>> x = list(p)

and

>>> x = p[:]

Since Python 3.3, the list object actually has a method intended for copying:从 Python 3.3 开始,列表对象实际上有一个用于复制的方法:

x = p.copy()

The slice is actually a very similar concept.切片实际上是一个非常相似的概念。 As nneonneo pointed out, however, that works only with objects such as lists and tuples that support slices.然而,正如 nneonneo 指出的那样,这仅适用于支持切片的列表和元组等对象。 The method you mention, however, works with any iterable: dictionaries, sets, generators, etc.但是,您提到的方法适用于任何可迭代对象:字典、集合、生成器等。

You should always throw these to dis and see what it throws back at you;你应该总是把这些扔给dis ,看看它向你扔回了什么; you'll see how *x, = p is actually different from x = p :您将看到*x, = p实际上与x = p有何不同:

dis('*x, = p')
  1           0 LOAD_NAME                0 (p)
              2 UNPACK_EX                0
              4 STORE_NAME               1 (x)

While, the simple assignment statement:而简单的赋值语句:

dis('x = p')
  1           0 LOAD_NAME                0 (p)
              2 STORE_NAME               1 (x)

(Stripping off unrelated None returns) (剥离无关的None返回)

As you can see UNPACK_EX is the different op-code between these;如您所见, UNPACK_EX是它们之间不同的操作码; it's documented as : 它记录为

Implements assignment with a starred target: Unpacks an iterable in TOS (top of stack) into individual values, where the total number of values can be smaller than the number of items in the iterable: one of the new values will be a list of all leftover items.使用带星号的目标实现赋值:将 TOS(栈顶)中的可迭代对象解包为单个值,其中值的总数可以小于可迭代对象中的项目数:新值之一将是所有值的列表剩余物品。

Which is why, as Eugene noted, you get a new object that's referred to by the name x and not a reference to an already existing object (as is the case with x = p ).这就是为什么,正如 Eugene 所指出的,您会得到一个由名称x引用的新对象,而不是对现有对象的引用(就像x = p的情况)。


*x, does seem very odd (the extra comma there and all) but it is required here. *x,看起来很奇怪(额外的逗号和所有)但这里是必需的。 The left hand side must either be a tuple or a list and, due to the quirkiness of creating a single element tuple in Python, you need to use a trailing , :左侧必须是元组或列表,并且由于在 Python 中创建单个元素元组的古怪性,您需要使用尾随,

i = 1, # one element tuple

If you like confusing people, you can always use the list version of this:如果您喜欢混淆他人,您可以随时使用此list版本:

[*x] = p

which does exactly the same thing but doesn't have that extra comma hanging around there.它做完全相同的事情,但没有多余的逗号挂在那里。

You can clearly understand it from below example你可以从下面的例子中清楚地理解它

L = [1, 2, 3, 4]
while L:
    temp, *L = L             
    print(temp, L)

what it does is, the front variable will get the first item every time and the remaining list will be given to L.它的作用是,front 变量每次都会得到第一项,而剩余的列表将提供给 L。

The output will look shown below.输出将如下所示。

1 [2, 3, 4]
2 [3, 4]
3 [4]
4 []

Also look at below example也看看下面的例子

x, *y, z = "python"
print(x,y,z)

In this both x,z will get each one letter from the string meaning first letter is assigned to x and the last letter will be assigned to z and the remaining string will be assigned to variable y.在这两个 x,z 都将从字符串中获取每个字母,这意味着第一个字母被分配给 x,最后一个字母将被分配给 z,其余的字符串将被分配给变量 y。

p ['y', 't', 'h', 'o'] n

One more example,再举一个例子,

a, b, *c = [0,1,2,3]
print(a,b,c)

0 1 [2,3]

Boundary case: If there is nothing remaining for star variable then it will get an empty list.边界情况:如果星型变量没有剩余,那么它将得到一个空列表。

Example:例子:

a,b=[1]
print(a,b)

1 []

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM