Неясность по поводу переменного поведения клонирования

Наряду с книгой мне была предоставлена ​​программа на 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):

  1. создает копию a (звонок a2)
  2. сцеплять da в a2 на месте
  3. вернуть a2

Тогда назначение a[:] = ...:

  1. заменяет все значения в 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)
Другие вопросы по тегам