0 added
0 removed
Original
2026-01-01
Modified
2026-03-10
1
<p>В этой статье мы поговорим, как скопировать массив в Python и чем копирование массива отличается от представления массива. Также рассмотрим поверхностное и глубокое копирование объектов в Python.</p>
1
<p>В этой статье мы поговорим, как скопировать массив в Python и чем копирование массива отличается от представления массива. Также рассмотрим поверхностное и глубокое копирование объектов в Python.</p>
2
<p>Работая с массивами в Python, вы наверняка сталкивались с ситуацией, когда при использовании некоторых функций, возвращающих какой-нибудь результат, с исходным массивом не происходит ничего. Как в примере ниже:</p>
2
<p>Работая с массивами в Python, вы наверняка сталкивались с ситуацией, когда при использовании некоторых функций, возвращающих какой-нибудь результат, с исходным массивом не происходит ничего. Как в примере ниже:</p>
3
<p>Всё дело в том, что в библиотеке NumPy есть два понятия касаемо массива:<strong>копия и представление</strong>. И это разные вещи. Посмотрите на код ниже:</p>
3
<p>Всё дело в том, что в библиотеке NumPy есть два понятия касаемо массива:<strong>копия и представление</strong>. И это разные вещи. Посмотрите на код ниже:</p>
4
<p>На самом деле, всё просто. Когда мы выполняем присваивание b = a, никакого копирования данных на деле не происходит. В памяти компьютера всё так же один массив, а переменные a и b - это даже не переменные, а<strong>указатели</strong>, указывающие на одни и те же данные. Таким образом, мы обращаемся по разным указателям к одним и тем же данным в памяти и видим в результате одно и то же.</p>
4
<p>На самом деле, всё просто. Когда мы выполняем присваивание b = a, никакого копирования данных на деле не происходит. В памяти компьютера всё так же один массив, а переменные a и b - это даже не переменные, а<strong>указатели</strong>, указывающие на одни и те же данные. Таким образом, мы обращаемся по разным указателям к одним и тем же данным в памяти и видим в результате одно и то же.</p>
5
<p>Хорошо, a и b являются указателями, но что тогда с переменной с? На деле, это тоже указатель, ссылающийся на ту же область памяти с данными, правда, представлены эти данные в иной форме. Вот мы и подошли к понятию<strong>представления массива</strong>, которое существует в NumPy. Действительно, те же данные можно представить в разной форме:</p>
5
<p>Хорошо, a и b являются указателями, но что тогда с переменной с? На деле, это тоже указатель, ссылающийся на ту же область памяти с данными, правда, представлены эти данные в иной форме. Вот мы и подошли к понятию<strong>представления массива</strong>, которое существует в NumPy. Действительно, те же данные можно представить в разной форме:</p>
6
<p>На деле, можно говорить о копировании,<strong>если данные в памяти компьютера физически копируются в другое место</strong>. Но, как мы уже убедились,<strong>операция присваивания копирование не выполняет</strong>. Также мы поняли, что те же самые данные могут иметь различные представления.</p>
6
<p>На деле, можно говорить о копировании,<strong>если данные в памяти компьютера физически копируются в другое место</strong>. Но, как мы уже убедились,<strong>операция присваивания копирование не выполняет</strong>. Также мы поняли, что те же самые данные могут иметь различные представления.</p>
7
<h2>Присваивание не копирует массивы в Python</h2>
7
<h2>Присваивание не копирует массивы в Python</h2>
8
<p>Итак, простое присваивание никаких копий массива не выполняет, и это первое, что стоит уяснить. Может показаться, что это всего лишь прихоть создателей Python и NumPy, но всё не так просто. Если бы ситуация обстояла иначе, мы бы работали с памятью напрямую, а отсутствие автоматического копирования во время присваивания - совсем небольшая плата за лёгкость и простоту языка программирования Python.</p>
8
<p>Итак, простое присваивание никаких копий массива не выполняет, и это первое, что стоит уяснить. Может показаться, что это всего лишь прихоть создателей Python и NumPy, но всё не так просто. Если бы ситуация обстояла иначе, мы бы работали с памятью напрямую, а отсутствие автоматического копирования во время присваивания - совсем небольшая плата за лёгкость и простоту языка программирования Python.</p>
9
<p>Давайте приведём ещё парочку примеров на эту тему:</p>
9
<p>Давайте приведём ещё парочку примеров на эту тему:</p>
10
<p>Обратите внимание, что массивы a и b в действительности являются одним и тем же массивом с такими же данными и типом данных.</p>
10
<p>Обратите внимание, что массивы a и b в действительности являются одним и тем же массивом с такими же данными и типом данных.</p>
11
<p>Таким образом, у нас есть массив b и массив a, но нельзя забывать о том, что это, по сути, один и тот же массив.</p>
11
<p>Таким образом, у нас есть массив b и массив a, но нельзя забывать о том, что это, по сути, один и тот же массив.</p>
12
<h2>Так как же копировать массивы в Python?</h2>
12
<h2>Так как же копировать массивы в Python?</h2>
13
<p>Чтобы сделать полную копию массива в Python, используют метод<strong>copy</strong>. Он выполняет копирование не только данных массива, но и всех его свойств.</p>
13
<p>Чтобы сделать полную копию массива в Python, используют метод<strong>copy</strong>. Он выполняет копирование не только данных массива, но и всех его свойств.</p>
14
<p>После применения метода copy мы можем говорить о массивах a и b,<strong>как о разных массивах и копиях друг друга</strong>. Да, эти массивы имеют одинаковые данные, но эти данные не являются одними и теми же. Теперь действительно массив<em>b</em>является копией массива<em>a</em>, и именно это называется копированием массива в терминологии NumPy.</p>
14
<p>После применения метода copy мы можем говорить о массивах a и b,<strong>как о разных массивах и копиях друг друга</strong>. Да, эти массивы имеют одинаковые данные, но эти данные не являются одними и теми же. Теперь действительно массив<em>b</em>является копией массива<em>a</em>, и именно это называется копированием массива в терминологии NumPy.</p>
15
<h2>Представление массива</h2>
15
<h2>Представление массива</h2>
16
<p>Итак, теперь мы знаем, как сделать копию массива посредством метода copy. Но бывают ситуации, когда нам не нужна копия массива, а нужен тот же массив но с иными размерами. Речь идёт, как вы уже догадались, о другом представлении исходного массива.</p>
16
<p>Итак, теперь мы знаем, как сделать копию массива посредством метода copy. Но бывают ситуации, когда нам не нужна копия массива, а нужен тот же массив но с иными размерами. Речь идёт, как вы уже догадались, о другом представлении исходного массива.</p>
17
<p>Для этих целей в NumPy есть метод ndarray.view(). Он создаёт новый объект массива, просматривающий данные исходного, однако изменение размеров одного массива не приводит к изменению размеров другого.</p>
17
<p>Для этих целей в NumPy есть метод ndarray.view(). Он создаёт новый объект массива, просматривающий данные исходного, однако изменение размеров одного массива не приводит к изменению размеров другого.</p>
18
<p>Обычно, функции которые меняют форму и порядок элементов в Пайтон-массивах возвращают не копию массива, а именно его представление:</p>
18
<p>Обычно, функции которые меняют форму и порядок элементов в Пайтон-массивах возвращают не копию массива, а именно его представление:</p>
19
<p>Также представлениями массивов в Python являются срезы массивов:</p>
19
<p>Также представлениями массивов в Python являются срезы массивов:</p>
20
<p>Обратите внимание, что когда мы говорим о том, что массив b является представлением массива a, мы подразумеваем, что вне зависимости от вида и формы массива b он включает в себя те же данные в памяти, что и наш массив a. Таким образом, изменение элементов в одном из массивов приведёт, соответственно, к изменениям в другом.</p>
20
<p>Обратите внимание, что когда мы говорим о том, что массив b является представлением массива a, мы подразумеваем, что вне зависимости от вида и формы массива b он включает в себя те же данные в памяти, что и наш массив a. Таким образом, изменение элементов в одном из массивов приведёт, соответственно, к изменениям в другом.</p>
21
<h2>Глубокое и поверхностное копирование объектов с помощью copy</h2>
21
<h2>Глубокое и поверхностное копирование объектов с помощью copy</h2>
22
<p>Как мы уже хорошо уяснили, операция присваивания не приводит к копированию объекта, а лишь создаёт ссылку на этот объект. Но если мы работаем с изменяемыми коллекциями или коллекциями, которые содержат изменяемые элементы, нам может понадобиться такая копия, которую мы сможем изменить, не меняя оригинал. Здесь нам тоже поможет copy, выполняющий как поверхностное, так и глубокое копирование: • copy.copy(a) - возвращает поверхностную копию a; • copy.deepcopy(a) - возвращает полную копию a.</p>
22
<p>Как мы уже хорошо уяснили, операция присваивания не приводит к копированию объекта, а лишь создаёт ссылку на этот объект. Но если мы работаем с изменяемыми коллекциями или коллекциями, которые содержат изменяемые элементы, нам может понадобиться такая копия, которую мы сможем изменить, не меняя оригинал. Здесь нам тоже поможет copy, выполняющий как поверхностное, так и глубокое копирование: • copy.copy(a) - возвращает поверхностную копию a; • copy.deepcopy(a) - возвращает полную копию a.</p>
23
<p>Если же объект скопировать невозможно, возникает исключение<strong>copy.error</strong>. В принципе, разница между глубоким и поверхностным копированием существенна лишь для составных объектов, которые содержат изменяемые объекты (допустим, список списков). При этом: 1)<strong>поверхностная копия</strong>позволяет создать новый составной объект, а потом (если это возможно) вставляет в него ссылки на объекты, которые находятся в оригинале; 2)<strong>глубокая копия</strong>позволяет создать новый составной объект, а потом рекурсивно вставляет в него копии объектов, которые находятся в оригинале.</p>
23
<p>Если же объект скопировать невозможно, возникает исключение<strong>copy.error</strong>. В принципе, разница между глубоким и поверхностным копированием существенна лишь для составных объектов, которые содержат изменяемые объекты (допустим, список списков). При этом: 1)<strong>поверхностная копия</strong>позволяет создать новый составной объект, а потом (если это возможно) вставляет в него ссылки на объекты, которые находятся в оригинале; 2)<strong>глубокая копия</strong>позволяет создать новый составной объект, а потом рекурсивно вставляет в него копии объектов, которые находятся в оригинале.</p>
24
>>> import copy >>> test_1 = [1, 2, 3, [1, 2, 3]] >>> test_copy = copy.copy(test_1) >>> print(test_1, test_copy) [1, 2, 3, [1, 2, 3]] [1, 2, 3, [1, 2, 3]] >>> test_copy[3].append(4) >>> print(test_1, test_copy) [1, 2, 3, [1, 2, 3, 4]] [1, 2, 3, [1, 2, 3, 4]] >>> test_1 = [1, 2, 3, [1, 2, 3]] >>> test_deepcopy = copy.deepcopy(test_1) >>> test_deepcopy[3].append(4) >>> print(test_1, test_deepcopy) [1, 2, 3, [1, 2, 3]] [1, 2, 3, [1, 2, 3, 4]]<p>При выполнении глубокого копирования возможны проблемы (их нет у поверхностного копирования): - рекурсивные объекты могут привести к рекурсивному циклу; - т. к. глубокая копия копирует всё, она способна скопировать слишком много, к примеру, административные структуры данных.</p>
24
>>> import copy >>> test_1 = [1, 2, 3, [1, 2, 3]] >>> test_copy = copy.copy(test_1) >>> print(test_1, test_copy) [1, 2, 3, [1, 2, 3]] [1, 2, 3, [1, 2, 3]] >>> test_copy[3].append(4) >>> print(test_1, test_copy) [1, 2, 3, [1, 2, 3, 4]] [1, 2, 3, [1, 2, 3, 4]] >>> test_1 = [1, 2, 3, [1, 2, 3]] >>> test_deepcopy = copy.deepcopy(test_1) >>> test_deepcopy[3].append(4) >>> print(test_1, test_deepcopy) [1, 2, 3, [1, 2, 3]] [1, 2, 3, [1, 2, 3, 4]]<p>При выполнении глубокого копирования возможны проблемы (их нет у поверхностного копирования): - рекурсивные объекты могут привести к рекурсивному циклу; - т. к. глубокая копия копирует всё, она способна скопировать слишком много, к примеру, административные структуры данных.</p>
25
<p>Однако в случае возникновения проблем нам поможет функция<strong>deepcopy</strong>, которая устраняет эти сложности: - посредством хранения "memo" словаря объектов; - позволяя классам, которые определяет пользователь, переопределять операцию копирования либо набор копируемых компонентов.</p>
25
<p>Однако в случае возникновения проблем нам поможет функция<strong>deepcopy</strong>, которая устраняет эти сложности: - посредством хранения "memo" словаря объектов; - позволяя классам, которые определяет пользователь, переопределять операцию копирования либо набор копируемых компонентов.</p>
26
>>> r = [1, 2, 3] >>> r.append(r) >>> print(r) [1, 2, 3, [...]] >>> p = copy.deepcopy(r) >>> print(p) [1, 2, 3, [...]]<p>В результате, не копируются типы вроде классов, функций, модулей, методов, стековых кадров, окон, сокетов и т. п.</p>
26
>>> r = [1, 2, 3] >>> r.append(r) >>> print(r) [1, 2, 3, [...]] >>> p = copy.deepcopy(r) >>> print(p) [1, 2, 3, [...]]<p>В результате, не копируются типы вроде классов, функций, модулей, методов, стековых кадров, окон, сокетов и т. п.</p>
27
<p>Что же, теперь, надеемся, вы получили представление о копировании массивов и объектов в Python. Если хотите знать больше, к вашим услугам специализированный курс для продвинутых разработчиков:</p>
27
<p>Что же, теперь, надеемся, вы получили представление о копировании массивов и объектов в Python. Если хотите знать больше, к вашим услугам специализированный курс для продвинутых разработчиков:</p>
28
<p>При написании материала использовались статьи: - "<a>Модуль copy - поверхностное и глубокое копирование объектов</a>"; - "<a>Копии и представления массивов</a>".</p>
28
<p>При написании материала использовались статьи: - "<a>Модуль copy - поверхностное и глубокое копирование объектов</a>"; - "<a>Копии и представления массивов</a>".</p>
29
29