Замена выражений в выражении (замена трех и более переменных) в Python

#python #python-3.x #variable-assignment

#python #python-3.x #переменная-присвоение #переменная-назначение

Вопрос:

Я попытался назначить три выражения в Python, но я получил неожиданный результат.

Давайте начнем с простых замен. Вы, вероятно, знаете результат этого назначения:

 A = [10, 11, 12]
p = 0
A[p   1], A[p] = A[p], A[p   1]    # <--
print(A)
  

Результат (как и ожидалось):

 [11, 10, 12]
  

Теперь я хотел быть немного более смелым, поэтому попробовал это назначение:

 A = [10, 11, 12]
p = 0
p, A[p   1], A[p] = p   1, A[p], A[p   1]   # <--
print(A)
  

Я думал, что результатом будет:

 [10, 12, 11]
  

Однако результат был:

 [10, 11, 10]
  

Что неожиданно!

Я прочитал документацию по Python, касающуюся назначений:

Хотя определение присваивания подразумевает, что совпадения между левой и правой сторонами являются ‘одновременными’ (например, a, b = b, a меняет местами две переменные), совпадения в коллекции присвоенных переменных происходят слева направо, иногда приводя к путанице. Например, следующая программа выводит [0, 2]:

 x = [0, 1]
i = 0
i, x[i] = 1, 2         # i is updated, then x[i] is updated
print(x)
  

Я не получил аналогичных результатов для своего swap. Я не понимаю логику, стоящую за моим обменом. Что происходит?

Комментарии:

1. Полученный вами результат был тем результатом, который вы должны были получить!

2. Не имеет прямого отношения к вашему вопросу, но docs.python.org/2.0/ref/assignment.html значительно устарел. Обратитесь к docs.python.org/3/reference /… или docs.python.org/2.7/reference /… для документации 3.X и 2.7 соответственно.

3. Это несколько похоже на написание кода на C, подобного x[i ]=i . Не делайте этого; даже если поведение четко определено, оно может быть не особенно понятным. Увеличьте значение p , затем выполните замену.

Ответ №1:

Вы можете рассматривать это как сокращение для последовательных назначений слева направо с использованием временных переменных:

 p, A[p   1], A[p] = p   1, A[p], A[p   1]
  

эквивалентно

 temp1  = p   1  # 1
temp2  = A[p]   # 10  (A[0])
temp3  = A[p 1] # 11  (A[1])
p      = temp1   # p    = 1
A[p 1] = temp2   # A[2] = 10
A[p]   = temp3   # A[1] = 11
  

итак A = [10,11,10]

Если вы разместите p в конце списка, вы, вероятно, приблизитесь к ожидаемому результату:

 A[p   1], A[p], p = A[p], A[p   1], p   1

A is now [11,10,12]
P is now 1
  

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

Вы могли бы сделать это, вручную вычисляя смещение в исходных данных, но это было бы несколько нелогично:

 p, A[p 1], A[p] = p 1, A[p 1], A[p 2]
  

Комментарии:

1. Соответствующая документация, для кого это может представлять интерес: docs.python.org/3/reference/expressions.html#evaluation-order

2. Спасибо за редактирование моего вопроса и благодарю за ваш соответствующий документ. @TrebledJ

3. спасибо за отличный ответ. Ты мне нравишься. Хороший ответ. Возможно ли объяснить эти две вещи: 1. предварительное включение и последующее включение 2.нелогичный @alain-t

4. Предварительное увеличение — это когда вы увеличиваете индекс (p) перед его использованием. постинкремент — это когда вы увеличиваете индекс после его использования. Что мне показалось нелогичным, так это то, что в моем последнем примере (с предварительным приращением) левая сторона присваивания принимает значение p, которое было увеличено, но правая сторона присваивания индексирует список с помощью p перед его увеличением (несмотря на то, что p 1 отображается перед исходными данными A [..]).