Подтвердить что ты не робот

Почему я не могу поменять два элемента в списке в одной строке?

Почему это не работает (значения не меняются):

lol = ["test","test2"]
lol[lol.index("test")], lol[lol.index("test2")] = lol[lol.index("test2")], lol[lol.index("test")]

Но это работает (значения меняются местами):

i1 = lol.index("test")
i2 = lol.index("test2")
lol[i1], lol[i2] = lol[i2], lol[i1]
4b9b3361

Ответ 1

Причина, по которой первый пример не работает, заключается в том, что вы вызываете .index() несколько раз, и после каждого раза значения в списке меняются, поэтому индексы, найденные в коде, не являются репрезентативными для фактических местоположений элементов. Второй пример работает, потому что вы сохранили первые индексы в двух переменных и используете оба в свопе.

Обзор первого примера:

lol[lol.index("test")], lol[lol.index("test2")] = lol[lol.index("test2")], lol[lol.index("test")] 

Первая часть: lol[lol.index("test")] хранит 0

Вторая часть: lol[lol.index("test2")] хранит 1

Третья часть: lol[lol.index("test2")] сохраняет 1

Это когда он становится интересным. Четвертая часть примера lol[lol.index("test")] находит индекс test, однако test был назначен 1 из третьего сегмента кода. Следовательно, lol[lol.index("test")] есть 1, а не 0. Следовательно, lol[lol.index("test2")] по-прежнему сохраняет 1.

Ответ 2

Объяснение

Все сводится к тому, чтобы понять, как работает порядок оценки, в частности случай expr3, expr4 = expr1, expr2.

Если мы выполним инструкцию lol[lol.index("test")], lol[lol.index("test2")] = lol[lol.index("test2")], lol[lol.index("test")], получим что-то вроде этого:

r1=evaluate(expr1) --> "test2"
r2=evaluate(expr2) --> "test"
evaluate(expr3)=r1 --> lol[0] = "test2" --> lol = ["test2","test2"]
evaluate(expr4)=r2 --> lol[0] = "test"  --> lol = ["test", "test2"]

Другой фрагмент тривиально:

i1 = lol.index("test")
i2 = lol.index("test2")
lol[i1], lol[i2] = lol[i2], lol[i1]

it1) i1 = 0
it2) i2 = 1
it3) lol[i1], lol[i2] = "test2", lol[i1]
it4) lol[i1], lol[i2] = "test2", "test"
it5) lol[i1] = "test2"
it6) lol[i2] = "test"

Альтернативы Oneliner

Что-то вроде этих:

lol = lol[lol.index("test2")], lol[lol.index("test")]

lol[0], lol[1] = lol[1], lol[0]

lol[0], lol[1] = lol[lol.index("test2")], lol[lol.index("test")]

Дополнительные примечания

Если вы действительно хотите узнать больше о том, как эти функции действительно интерпретируются, очень хороший способ сделать это - использовать модуль dis, например:

>>> import dis
>>> def f():
...    lst[lst.index(str1)], lst[lst.index(str2)] = lst[lst.index(str2)], lst[lst.index(str1)]
...
>>> dis.dis(f)
  2           0 LOAD_GLOBAL              0 (lst)
              3 LOAD_GLOBAL              0 (lst)
              6 LOAD_ATTR                1 (index)
              9 LOAD_GLOBAL              2 (str2)
             12 CALL_FUNCTION            1
             15 BINARY_SUBSCR
             16 LOAD_GLOBAL              0 (lst)
             19 LOAD_GLOBAL              0 (lst)
             22 LOAD_ATTR                1 (index)
             25 LOAD_GLOBAL              3 (str1)
             28 CALL_FUNCTION            1
             31 BINARY_SUBSCR
             32 ROT_TWO
             33 LOAD_GLOBAL              0 (lst)
             36 LOAD_GLOBAL              0 (lst)
             39 LOAD_ATTR                1 (index)
             42 LOAD_GLOBAL              3 (str1)
             45 CALL_FUNCTION            1
             48 STORE_SUBSCR
             49 LOAD_GLOBAL              0 (lst)
             52 LOAD_GLOBAL              0 (lst)
             55 LOAD_ATTR                1 (index)
             58 LOAD_GLOBAL              2 (str2)
             61 CALL_FUNCTION            1
             64 STORE_SUBSCR
             65 LOAD_CONST               0 (None)
             68 RETURN_VALUE
>>>

Ответ 3

Поскольку X,Y="test","test2" будет обрабатываться как X="test";Y="test2"

lol = ["test","test2"]
lol[lol.index("test")], lol[lol.index("test2")] = lol[lol.index("test2")], lol[lol.index("test")]

Сначала правая сторона получит оценку, поэтому вы получите:

lol[lol.index("test")], lol[lol.index("test2")] = "test2", "test"

который будет иметь тот же эффект, что и следующие строки:

lol[lol.index("test")]="test2"
#   returns 0
# lol==["test2","test2"]
lol[lol.index("test2")]="test"
#  returns 0