Единственное место, где мне действительно нужно было использовать его, - это функция eval. Проблема с eval заключается в том, что, когда строка не может быть проанализирована из-за ошибки синтаксиса, eval не возвращает false, а скорее выдает ошибку, точно так же, как наличие ошибки синтаксического анализа в регулярном скрипте. Чтобы проверить, является ли скрипт, хранящийся в строке, синтаксическим, вы можете использовать что-то вроде:
$script_ok = @eval('return true; '.$script);
AFAIK, это самый элегантный способ сделать это.
Когда Вы пишете [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.
На самом деле это точно, что Вы ожидали бы. Давайте анализировать то, что происходит здесь:
Вы пишете
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, ведя к различному списку.
[[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]]
, где это, вероятно, немного менее удивительно.
@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].