Неясность по поводу переменного поведения клонирования
Наряду с книгой мне была предоставлена программа на Python, в которую я сейчас углубляюсь.
Программа использует глобальную структуру данных с именем globdat
в определенной подпрограмме массив numpy внутри globdat
присваивается локальной переменной:
a = globdat.array
Затем в следующем цикле while переменная a
обновляется каждую итерацию в соответствии с:
a[:] += da[:]
Результатом этой операции является то, что globdat.array
обновляется, что используется в последующих операциях.
Является ли использование [:]
требуется здесь, или это просто используется, чтобы указать, что он также клонирует в globdat.array
? Кто-нибудь может уточнить этот стиль кодирования?
3 ответа
Второй [:]
, в правой части, является избыточным. Это просто копии da
перед использованием в конкатенации, что бессмысленно.
Мы остались с:
a[:] += da
Для начала давайте разберемся, что a += da
делает. Он сопоставляется с:
a = a.__iadd__(da)
Призыв к __iadd__
расширяет первоначальный список a
и возвращает self
ссылка на список. Тогда присвоение, которое происходит после, не имеет никакого эффекта (так же, как a=a
).
Это достигает первоначальной цели, то есть расширить глобальный массив.
Теперь, что делает a[:] += da
делать? Он сопоставляется с:
a[:] = a[:].__iadd__(da)
Или более утомительно:
a.__setitem__(slice(None), a.__getitem__(slice(None)).__iadd__(da))
Для удобства чтения напишем его как (не правильный синтаксис Python):
a.__setitem__(:, a.__getitem__(:).__iadd__(da))
Так a[:].__iadd__(da)
:
- создает копию
a
(звонокa2
) - сцеплять
da
вa2
на месте - вернуть
a2
Тогда назначение a[:] = ...
:
- заменяет все значения в
a
со всеми значениями вa2
на месте.
Так что это тоже, достигает первоначальной цели, но менее эффективно.
В ответах на этот вопрос есть некоторые интересные детали об этом материале.
Если вы хотите изменить список на месте, а не заменить его новым списком, вам нужно использовать синтаксис срезов.
a[:] = da[:]
В этом случае, хотя, +=
всегда будет изменять список на месте, поэтому нарезка будет избыточной.
Это может быть прекрасным примером программирования культа грузов.
Это утверждение довольно противно:
a[:] += da[:]
Это переводится на это:
a.__setitem__(slice(None),
a.__getitem__(slice(None)).__iadd__(da.__getitem__(slice(None))))
Это делает ненужные копии обоих списков.
Если предположить, a
а также da
списки, вы могли бы более разумно использовать extend()
метод:
a.extend(da)