#python #numpy
#python #numpy
Вопрос:
Я знаю, что для следующего:
a=1
b=a
a=4
Он присваивает 1
значение to a
, а затем a
to b
, за которым следует изменение значения a
to 4
в качестве последнего шага.
Здесь, как только значение a
будет изменено на 4
, никаких изменений в значении не будет b
.
Аналогично для
a=np.array([10,20,30,40,50,60])
b=a[2]
a[2]=100
значение b
в конце кода будет 20
таким, которое было начальным a[2]
.
Но когда у вас есть что-то, как указано ниже:
a=np.array([10,20,30,40,50,60])
b=a[0:2]
и если мы изменимся a[0:2]=[100,200]
, значение b
также изменится автоматически. Похоже, что переменная b
связана каким-то другим образом (что отличалось от предыдущих случаев).
И я знаю, что если код написан как b=a[0:2].copy()
, то b
он не изменится, даже если a
будет изменен.
Итак, мой вопрос в том, где именно я должен использовать этот .copy()
метод, если я не хочу изменять последнюю переменную, потому что в первых двух случаях в этом не было необходимости
Ценю вашу помощь
Комментарии:
1. Является ли ваш вопрос специфичным для
numpy
(который имеет нестандартные механизмы нарезки) или о Python в целом (где нарезка почти всегда является неглубокой копией, единственным исключением из встроенных модулей, которые, как я знаю, являютсяmemoryview
типом). Я предполагаю, что первое (поведение, которое вас смущает, в значительной степени уникально дляnumpy
пакетов и основано на нем), но.copy()
это метод для стольких типов, что он неясен. Я отмечу: правила всегда будут зависеть от задействованных типов; нарезка не имеет гарантированного поведения, поэтому вам нужно знать, какие правила существуют для этого типа.2. @ShadowRanger Спасибо за ответ. Итак, если мы сосредоточимся на
numpy
… Здесь, в моем втором примере, который представляет собой массив numpy, он не влияет на переменнуюb
. Но в третьем случае это так. Итак, можете ли вы предложить подходящий способ определить, связаны ли переменные или нет..
Ответ №1:
В первом и втором случаях вы присвоили одно значение (скалярное) b
.
В третьем случае вы назначили представление 0:2
на основе фрагмента a
b
to (см. basic-slicing-and-indexing ). Это, по сути, многозначная ссылка на определенные элементы a
(т. Е.: b[0]
Действительно относится к a[0]
). Другими словами, b
не владеет своими данными, но указывает на данные в a
. Таким образом, при изменении a
b
просто отражает эти изменения, потому что оно указывает на те же самые элементы.
В общем, вам следует использовать numpy copy()
, например, когда вы хотите отделить копию от оригинала:
- когда вы собираетесь внести изменения в копию (например, не круто незаметно изменять данные вызывающего абонента),
- если вы хотите сохранить моментальный снимок массива в этот момент, независимо от того, что произойдет с оригиналом позже,
- когда у вас очень разреженная нарезка или в случайном порядке, и вы хотите получить более компактную копию для более быстрых операций (локальность ссылки),
- когда вы хотите изменить флаги
a
илиb
(например, с C-continuous на F-continuous, опять же, обычно по соображениям скорости).
Что касается вашего вопроса в комментариях «есть ли какой-либо способ определить, связаны ли переменные или нет»: да. Каждый массив numpy имеет flags
:
a=np.array([10,20,30,40,50,60])
b=a[2]
b.flags.owndata
# True -- funny given that b is a single numpy.int64, but it still has flags
b=a[0:2]
b.flags.owndata
# False
a=np.array([10,20,30,40,50,60])
b=a[0:2].copy()
b.flags.owndata
# True
Комментарии:
1. Это неправильно »
b
, будучи мелкой копией, также влияет.»b
не является мелкой копией; если бы это было так, переназначение элементов верхнего уровня в нем илиa
(и в нем есть только элементы верхнего уровня, являющиеся массивом 1D) не изменило бы другое.b
является представлением частиa
, во многом таким же образомsomedict.items()
(на Python 3) является представлением базовогоdict
(поэтому изменениеdict
изменяет представление элементов).2. Если я не ошибаюсь, то это не фрагмент, а представление (я даже проверил эту документацию там, она никогда не вызывает результат нарезки фрагмента).
3. @ShadowRanger и @superbrain вы оба правы в том, что это представление. Это фактическое имя объекта. В данном случае срезом является сам диапазон
0:2
. Помимо именования, все дело в том, что, если я не ошибаюсь, представление просто содержит указатели (ссылки) на значения вa
.4. @PierreD: Да, мое возражение было конкретно против термина «мелкая копия» (поскольку фактического копирования не происходило). После редактирования формулировка верна; проголосовал (и удалил мой собственный ответ, поскольку ваши правки добавили недостающую дополнительную информацию и оправдали мой собственный ответ).