В чём разница между view и copy в Pandas и почему это важно?
View разделяет память с исходным DataFrame — изменение одного меняет другой; copy — независимый объект в отдельной памяти. Pandas не всегда предсказуем, поэтому используйте явный .copy() везде, где нужна независимость.
View и Copy в Pandas
Понимание разницы между view и copy критично: неправильное предположение о том, какой из них вы держите, приводит либо к потере данных, либо к неожиданным мутациям исходного DataFrame.
Что такое view
View — объект, разделяющий память с исходным массивом. Изменение view отражается на оригинале и наоборот. Это работает на уровне NumPy.
import pandas as pd
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
view = arr[1:4] # numpy view
view[0] = 99
print(arr) # [1, 99, 3, 4, 5] — оригинал изменён!
Что такое copy
Copy — независимый объект со своей памятью. Изменения не распространяются на родителя.
cp = arr[1:4].copy()
cp[0] = 0
print(arr) # [1, 99, 3, 4, 5] — оригинал не изменён
Непредсказуемость в Pandas
В Pandas результат операции индексации — view или copy — зависит от внутренней структуры блоков данных. Pandas объединяет столбцы одного dtype в один NumPy массив; слайс по такому массиву — view. Слайс, затрагивающий разные dtype — copy.
df = pd.DataFrame({
"a": [1, 2, 3],
"b": [4, 5, 6],
"c": [7, 8, 9],
}) # все int64 → один блок → слайс даст view
# Может быть view:
sub = df[["a", "b"]]
sub["a"] = 0 # SettingWithCopyWarning — неопределённое поведение
print(df) # a может быть изменён или нет — зависит от версии Pandas
Как проверить: view или copy
# Способ 1: _is_copy (устарело в Pandas 2.x)
print(sub._is_copy) # weakref или None
# Способ 2: проверить base numpy array
def is_view(df_or_series):
arr = df_or_series.values
return arr.base is not None
print(is_view(df["a"])) # зависит от dtype и структуры
# Способ 3: id памяти
import ctypes
print(df["a"].values.ctypes.data == sub["a"].values.ctypes.data)
Явный .copy() — правильное решение
# ВСЕГДА используйте .copy() при работе с подмножеством
moscow = df[df["a"] > 1].copy()
moscow["b"] = 999
print(df) # Оригинал не изменён — гарантировано
# При создании производного DataFrame
df2 = df.assign(d=df["a"] + df["b"]) # assign всегда возвращает копию
# Функции, не мутирующие вход — явный контракт
def process(df: pd.DataFrame) -> pd.DataFrame:
result = df.copy()
result["processed"] = result["a"] * 2
return result
Copy-on-Write (CoW) в Pandas 2.0+ и 3.0
# Pandas 2.0: включить CoW
pd.options.mode.copy_on_write = True
# Pandas 3.0: CoW включён по умолчанию
# Любой slice теперь lazy copy:
# — пока не изменён, разделяет память (экономия RAM)
# — при первом изменении автоматически копируется
df = pd.DataFrame({"a": [1, 2, 3]})
sub = df[["a"]] # lazy: пока view
sub["a"] = 99 # при записи: автоматически копируется
print(df) # Оригинал не изменён
print(sub) # Изменён только sub
Подводные камни
- В Pandas до 3.0 нельзя предсказать view или copy без проверки dtype и структуры блоков — всегда используйте явный
.copy()для безопасности. - Код, опирающийся на propagation через view (
sub["a"] = 1изменяетdf), сломается с CoW в Pandas 3.0. .loc[]и.iloc[]при выборке по строкам могут возвращать и view, и copy в зависимости от сложности маски..valuesвозвращает numpy array — изменениеdf.values[0, 0] = 999может мутировать DataFrame, обходя все защитные механизмы Pandas.- После
pd.concat()результат — всегда новый объект (copy), но составляющие его блоки могут быть view на исходные массивы до CoW. deep=Trueв.copy(deep=True)— дефолт, копирует и данные, и индекс.deep=Falseкопирует только метаданные структуры, но не данные.- В многопоточном коде view без блокировок ведёт к гонке данных — в таких сценариях всегда передавайте
.copy().
Common mistakes
- Объяснять
view vs copyтолько синтаксисом без shape, dtype, состояния или режима выполнения. - Игнорировать leakage, воспроизводимость, пустые входы и скрытые копии данных.
- Не проверять production-симптомы: latency, память, ретраи, дрейф качества и несовпадение версий.
What the interviewer is testing
- Может ли связать
view vs copyс реальным контрактом входов и выходов. - Упоминает ли тесты, метрики, reproducibility и диагностику ошибок.
- Видит ли различие между demo-кодом в ноутбуке и production-пайплайном.
- Предлагает ли observability, rollback, ограничения стоимости и стратегию incident replay.