При построении структур данных путем объединения частей старых структур данных Python всегда выполняет поверхностное копирование? - PullRequest
0 голосов
/ 04 ноября 2018

Если я создам новый список из некоторых существующих элементов в списке, будет ли python затем копировать элементы в новый список?

Вот пример кода, чтобы уточнить, что я имею в виду:

structure = [] 
structure.append([pd.read_excel("df1.csv"), item1]) #contains a large dataframe, df1, and some other object, item1
structure.append([pd.read_excel("df2.csv"), item2]) #analoguous

lst = [structure[0][0]["some_column1"], structure[1][0]["some_column2"]] #here we save just the dataframe

При выполнении других подобных операций по извлечению содержимого из существующих структур данных и вставке его в новые структуры данных (без предоставления какой-либо явной инструкции для выполнения глубокого копирования), существует ли какое-то правило, когда Python будет выполнять поверхностное копирование? Или может в некоторых случаях случиться так, что механизм копирования по умолчанию будет глубоким?

1 Ответ

0 голосов
/ 04 ноября 2018

Переменные в Python - это всегда ссылки (умные указатели) на объекты в куче. В Python нет понятия об объектах, живущих в стеке, как в C. Присвоение значения новому имени в Python не копирует его, оно просто добавляет ссылку на объект.

Список Python также является списком этих ссылок. Помещение существующего объекта кучи в список Python просто добавляет ссылку на него. Это не копирует это. Метод foo.copy() или foo[:] full slice (где foo - список) делает поверхностную копию. Точно так же list(foo) или [*foo] это мелкая копия. В модуле copy есть функция глубокого копирования, если это то, что вам нужно.

Правила могут быть разными для массивов. Рамки данных Pandas основаны на массивах Numpy. Хотя они могут содержать указатели (например, для строк, которые могут иметь переменную длину), они также могут содержать значения в строке без ссылок, что типично для массивов чисел.

Многомерные массивы Numpy этих типов, в отличие от списков списков, не могут быть скопированы, поскольку они вообще не содержат указателей. Но, в отличие от встроенных коллекций Python, нарезка массивов Numpy обычно делает «просмотр» одного и того же массива, но в некоторых случаях это невозможно, и Numpy должен сделать копию.

Получение значения из такого массива означает создание копии значения в виде объекта кучи, чтобы Python мог иметь прямую ссылку на него. Конечно, вы можете создать новую ссылку на массив в целом, назначив его новой переменной или поместив в список. Но, конечно, это не копирует массив вообще.


Итак, просто чтобы подтвердить, это означает, что мой lst является глубокой копией частей структур панд?

Нет (вероятно). Вы создали новый список, но он (вероятно) содержит ссылки на те же объекты столбцов, что и кадр данных, или, по крайней мере, «просмотры» того же.

Большинство операций в Pandas будут делать копии, если вы не используете аргумент inplace=True (который недоступен даже для некоторых операций). Конечно, назначения для индекса выполняются, но остерегайтесь косвенного цепного индексирования , что может привести к тому, что вместо этого будет назначена копия.

При получении по индексу Pandas попытается использовать представление для эффективности, но, как и для массивов Numpy, на которых он основан, это не всегда возможно (например, когда объект имеет несколько dtypes). Я не могу точно сказать, что применимо, не зная структуры вашего информационного кадра, а может быть, даже тогда, но я думаю, что это будет мелкая копия. Это может быть трудно предсказать вне простых случаев, и это может зависеть от макета памяти, который выбрал Панд, который является деталью реализации, которая может быть изменена без уведомления. Не рассчитывай на это. Будьте явными и используйте методы копирования.

...