理解 *x ,= lst
Understanding *x ,= lst
我正在浏览一些旧代码试图理解它的作用,我遇到了这个奇怪的陈述:
*x ,= p
p
是此上下文中的列表。我一直在试图弄清楚这个声明的作用。据我所知,它只是将 x
设置为 p
的值。例如:
p = [1,2]
*x ,= p
print(x)
刚给
[1, 2]
那么这与 x = p
有什么不同吗?知道这个语法在做什么吗?
*x ,= p
基本上是使用 extended iterable unpacking 的 x = list(p)
的混淆版本。 x
之后的逗号是使赋值目标成为一个元组所必需的(尽管它也可以是一个列表)。
*x, = p
是不同于x = p
因为前者创建了p
的copy (即一个新列表)而后者创建一个 reference 到原始列表。举例说明:
>>> p = [1, 2]
>>> *x, = p
>>> x == p
True
>>> x is p
False
>>> x = p
>>> x == p
True
>>> x is p
True
这是 Python 3.0 (PEP 3132) 中引入的一项功能。在 Python 2 中,你可以这样做:
>>> p = [1, 2, 3]
>>> q, r, s = p
>>> q
1
>>> r
2
>>> s
3
Python 3 对此进行了扩展,以便一个变量可以包含多个值:
>>> p = [1, 2, 3]
>>> q, *r = p
>>> q
1
>>> r
[2, 3]
因此,这就是此处使用的内容。然而,它不是两个变量来保存三个值,而是一个变量来获取列表中的每个值。这与 x = p
不同,因为 x = p
只是意味着 x
是 p
的另一个名称。然而,在这种情况下,它是一个新列表,其中恰好具有相同的值。 (您可能对"Least Astonishment" and the Mutable Default Argument感兴趣)
另外两种产生这种效果的常见方法是:
>>> x = list(p)
和
>>> x = p[:]
从Python 3.3开始,列表对象实际上有一个用于复制的方法:
x = p.copy()
切片实际上是一个非常相似的概念。然而,正如 nneonneo 指出的那样,这仅适用于支持切片的对象,例如列表和元组。但是,您提到的方法适用于任何可迭代对象:字典、集合、生成器等。
你应该总是把这些扔给 dis
看看它会把什么扔给你;您会看到 *x, = p
与 x = p
:
实际上有何不同
dis('*x, = p')
1 0 LOAD_NAME 0 (p)
2 UNPACK_EX 0
4 STORE_NAME 1 (x)
而简单的赋值语句:
dis('x = p')
1 0 LOAD_NAME 0 (p)
2 STORE_NAME 1 (x)
(剥离无关None
returns)
如您所见,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.
这就是为什么,正如 Eugene 指出的那样,您会得到一个由名称 x
引用的新对象,而不是对已存在对象的引用(x = p
就是这种情况) .
*x,
确实看起来很奇怪(那里多余的逗号)但这里是必需的。左侧必须是元组或列表,并且由于在 Python 中创建单个元素元组的古怪之处,您需要使用尾随 ,
:
i = 1, # one element tuple
如果你喜欢混淆别人,你可以随时使用这个的 list
版本:
[*x] = p
它做的事情完全一样,但没有多余的逗号。
你可以从下面的例子中清楚地理解它
L = [1, 2, 3, 4]
while L:
temp, *L = L
print(temp, L)
它的作用是,front变量每次都会取第一项,剩下的列表给L。
输出如下所示。
1 [2, 3, 4]
2 [3, 4]
3 [4]
4 []
另请看下面的例子
x, *y, z = "python"
print(x,y,z)
在这两个 x,z 都会从字符串中获取每个字母,这意味着第一个字母被分配给 x,最后一个字母将被分配给 z,剩下的字符串将被分配给变量 y。
p ['y', 't', 'h', 'o'] n
再举一个例子,
a, b, *c = [0,1,2,3]
print(a,b,c)
0 1 [2,3]
边界情况:如果 star 变量没有剩余,那么它将得到一个空列表。
示例:
a,b=[1]
print(a,b)
1 []
我正在浏览一些旧代码试图理解它的作用,我遇到了这个奇怪的陈述:
*x ,= p
p
是此上下文中的列表。我一直在试图弄清楚这个声明的作用。据我所知,它只是将 x
设置为 p
的值。例如:
p = [1,2]
*x ,= p
print(x)
刚给
[1, 2]
那么这与 x = p
有什么不同吗?知道这个语法在做什么吗?
*x ,= p
基本上是使用 extended iterable unpacking 的 x = list(p)
的混淆版本。 x
之后的逗号是使赋值目标成为一个元组所必需的(尽管它也可以是一个列表)。
*x, = p
是不同于x = p
因为前者创建了p
的copy (即一个新列表)而后者创建一个 reference 到原始列表。举例说明:
>>> p = [1, 2]
>>> *x, = p
>>> x == p
True
>>> x is p
False
>>> x = p
>>> x == p
True
>>> x is p
True
这是 Python 3.0 (PEP 3132) 中引入的一项功能。在 Python 2 中,你可以这样做:
>>> p = [1, 2, 3]
>>> q, r, s = p
>>> q
1
>>> r
2
>>> s
3
Python 3 对此进行了扩展,以便一个变量可以包含多个值:
>>> p = [1, 2, 3]
>>> q, *r = p
>>> q
1
>>> r
[2, 3]
因此,这就是此处使用的内容。然而,它不是两个变量来保存三个值,而是一个变量来获取列表中的每个值。这与 x = p
不同,因为 x = p
只是意味着 x
是 p
的另一个名称。然而,在这种情况下,它是一个新列表,其中恰好具有相同的值。 (您可能对"Least Astonishment" and the Mutable Default Argument感兴趣)
另外两种产生这种效果的常见方法是:
>>> x = list(p)
和
>>> x = p[:]
从Python 3.3开始,列表对象实际上有一个用于复制的方法:
x = p.copy()
切片实际上是一个非常相似的概念。然而,正如 nneonneo 指出的那样,这仅适用于支持切片的对象,例如列表和元组。但是,您提到的方法适用于任何可迭代对象:字典、集合、生成器等。
你应该总是把这些扔给 dis
看看它会把什么扔给你;您会看到 *x, = p
与 x = p
:
dis('*x, = p')
1 0 LOAD_NAME 0 (p)
2 UNPACK_EX 0
4 STORE_NAME 1 (x)
而简单的赋值语句:
dis('x = p')
1 0 LOAD_NAME 0 (p)
2 STORE_NAME 1 (x)
(剥离无关None
returns)
如您所见,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.
这就是为什么,正如 Eugene 指出的那样,您会得到一个由名称 x
引用的新对象,而不是对已存在对象的引用(x = p
就是这种情况) .
*x,
确实看起来很奇怪(那里多余的逗号)但这里是必需的。左侧必须是元组或列表,并且由于在 Python 中创建单个元素元组的古怪之处,您需要使用尾随 ,
:
i = 1, # one element tuple
如果你喜欢混淆别人,你可以随时使用这个的 list
版本:
[*x] = p
它做的事情完全一样,但没有多余的逗号。
你可以从下面的例子中清楚地理解它
L = [1, 2, 3, 4]
while L:
temp, *L = L
print(temp, L)
它的作用是,front变量每次都会取第一项,剩下的列表给L。
输出如下所示。
1 [2, 3, 4]
2 [3, 4]
3 [4]
4 []
另请看下面的例子
x, *y, z = "python"
print(x,y,z)
在这两个 x,z 都会从字符串中获取每个字母,这意味着第一个字母被分配给 x,最后一个字母将被分配给 z,剩下的字符串将被分配给变量 y。
p ['y', 't', 'h', 'o'] n
再举一个例子,
a, b, *c = [0,1,2,3]
print(a,b,c)
0 1 [2,3]
边界情况:如果 star 变量没有剩余,那么它将得到一个空列表。
示例:
a,b=[1]
print(a,b)
1 []