Понимание *x,= lst

Я перебираю какой-то старый код, пытаясь понять, что он делает, и наткнулся на это странное утверждение:

*x ,= p

p это список в этом контексте. Я пытался выяснить, что делает это утверждение. Насколько я могу сказать, это просто устанавливает x к стоимости p, Например:

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

Просто дает

[1, 2]

Так чем это отличается от x = p? Есть идеи, что делает этот синтаксис?

3 ответа

Решение

*x ,= p в основном запутанная версия x = list(p) используя расширенную повторяемую распаковку. Запятая после x требуется, чтобы назначение назначения было кортежем (хотя это также может быть список).

*x, = p отличается от x = p потому что первый создает копию p (т.е. новый список), в то время как последний создает ссылку на исходный список. Проиллюстрировать:

>>> 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, В этом случае, однако, это новый список, который просто содержит те же значения. (Возможно, вас заинтересуют "Наименьшее изумление" и изменяемый аргумент по умолчанию)

Два других распространенных способа создания этого эффекта:

>>> 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возвраты)

Как вы видете UNPACK_EX это другой код операции между ними; это задокументировано как:

Реализует присваивание с помеченной звездочкой целью: распаковывает итерируемое в TOS (начало стека) в отдельные значения, где общее количество значений может быть меньше, чем количество элементов в итерируемом: одно из новых значений будет списком всех остатки предметов.

Вот почему, как заметил Юджин, вы получаете новый объект, который называется по имени 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]

Граничный случай: если для звездной переменной ничего не осталось, она получит пустой список.

Пример:

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

1 []
Другие вопросы по тегам