Изменения в списках, отраженные по всем спискам неожиданно

Единственное место, где мне действительно нужно было использовать его, - это функция eval. Проблема с eval заключается в том, что, когда строка не может быть проанализирована из-за ошибки синтаксиса, eval не возвращает false, а скорее выдает ошибку, точно так же, как наличие ошибки синтаксического анализа в регулярном скрипте. Чтобы проверить, является ли скрипт, хранящийся в строке, синтаксическим, вы можете использовать что-то вроде:

$script_ok = @eval('return true; '.$script);

AFAIK, это самый элегантный способ сделать это.

530
задан Taryn 22 March 2017 в 16:14
поделиться

4 ответа

Когда Вы пишете [x]*3, Вы получаете, по существу, список [x, x, x]. Таким образом, список с 3 ссылками на тот же x. Когда Вы тогда изменяете этот сингл x, это видимо через все три ссылки на него.

Для фиксации его необходимо удостовериться, что Вы создаете новый список в каждом положении. Один способ сделать это

[[1]*4 for _ in range(3)]

, который переоценит [1]*4 каждый раз вместо того, чтобы оценить его однажды и сделать 3 ссылки на 1 список.

<час>

Вы могли бы задаться вопросом, почему * не может сделать независимые объекты путем, понимание списка делает. Поэтому оператор умножения * воздействует на объекты, не видя выражения. Когда Вы используете * для умножения [[1] * 4] на 3, * только видит, что список с 1 элементом [[1] * 4] оценивает к, не [[1] * 4 текст выражения. * понятия не имеет, как сделать копии того элемента, никакая идея, как переоценить [[1] * 4], и никакая идея, Вы даже хотите копии, и в целом, даже не могло бы быть способа скопировать элемент.

единственная опция * имеет, должен сделать новые ссылки на существующий подсписок вместо того, чтобы пытаться сделать новые подсписки. Что-либо еще было бы непоследовательно или потребовало бы основного перепроектирования фундаментальных проектных решений языка.

Напротив, понимание списка переоценивает выражение элемента на каждом повторении. [[1] * 4 for n in range(3)] переоценивает [1] * 4, каждый раз по той же причине [x**2 for x in range(3)] переоценивает x**2 каждый раз. Каждая оценка [1 120] генерирует новый список, таким образом, понимание списка делает то, что Вы хотели.

Кстати, [1] * 4 также не копирует элементы [1 122], но это не имеет значения, так как целые числа неизменны. Вы не можете сделать чего-то как [1 123] и превратить 1 в 2.

457
ответ дан Jean-François Fabre 22 March 2017 в 16:14
поделиться

На самом деле это точно, что Вы ожидали бы. Давайте анализировать то, что происходит здесь:

Вы пишете

lst = [[1] * 4] * 3

, Это эквивалентно:

lst1 = [1]*4
lst = [lst1]*3

Это означает lst, список с 3 элементами все указывающие lst1. Это означает, что два после строк эквивалентны:

lst[0][0] = 5
lst1[0] = 5

Как lst[0] только lst1.

Для получения желаемого поведения можно использовать понимание списка:

lst = [ [1]*4 for n in xrange(3) ]

В этом случае, выражение переоценено для каждого n, ведя к различному списку.

44
ответ дан PierreBdR 22 March 2017 в 16:14
поделиться
[[1] * 4] * 3

или даже:

[[1, 1, 1, 1]] * 3

Создает список, который ссылается на внутреннее [1,1,1,1] 3 раза - не три копии внутреннего списка, таким образом, любое время, Вы изменяете список (в любом положении), Вы будете видеть изменение три раза.

Это совпадает с этим примером:

>>> inner = [1,1,1,1]
>>> outer = [inner]*3
>>> outer
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
>>> inner[0] = 5
>>> outer
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]

, где это, вероятно, немного менее удивительно.

31
ответ дан Jim Fasarakis Hilliard 22 March 2017 в 16:14
поделиться

@spelchekr от [1 112] умножение списка Python: [[...]] *3 входит в 3 списка, которые зеркально отражают друг друга, когда изменено , и у меня был тот же вопрос о, "Почему делает только внешнее *3, создают больше ссылок, в то время как внутренний не делает? Почему все это не 1 с?"

li = [0] * 3
print([id(v) for v in li]) # [140724141863728, 140724141863728, 140724141863728]
li[0] = 1
print([id(v) for v in li]) # [140724141863760, 140724141863728, 140724141863728]
print(id(0)) # 140724141863728
print(id(1)) # 140724141863760
print(li) # [1, 0, 0]

ma = [[0]*3] * 3 # mainly discuss inner & outer *3 here
print([id(li) for li in ma]) # [1987013355080, 1987013355080, 1987013355080]
ma[0][0] = 1
print([id(li) for li in ma]) # [1987013355080, 1987013355080, 1987013355080]
print(ma) # [[1, 0, 0], [1, 0, 0], [1, 0, 0]]

Вот мое объяснение после попытки кода выше:

  • внутреннее *3 также создает ссылки, но это - ссылки, неизменны, что-то как [&0, &0, &0], затем когда измениться li[0], Вы не можете изменить базовую ссылку интервала константы 0, таким образом, можно просто изменить ссылочный адрес в новый &1;
  • , в то время как ma=[&li, &li, &li] и li изменяемо, поэтому когда Вы звоните ma[0][0]=1, мама [0] [0] одинаково к &li[0], таким образом, весь эти &li экземпляры изменят его 1-й адрес в [1 111].
1
ответ дан 22 November 2019 в 22:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: