0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>В Python в отличие от других языков, нет разделения на примитивные типы и ссылочные. Все всегда передается по ссылке. Почему об этом нужно знать?</p>
1
<p>В Python в отличие от других языков, нет разделения на примитивные типы и ссылочные. Все всегда передается по ссылке. Почему об этом нужно знать?</p>
2
<p>С точки зрения прикладного программиста, разница проявляется при изменении данных, их передаче и возврате из функций. Нужно держать в уме, что списки как коллекции хранят в себе не сами значения, а ссылки на них.</p>
2
<p>С точки зрения прикладного программиста, разница проявляется при изменении данных, их передаче и возврате из функций. Нужно держать в уме, что списки как коллекции хранят в себе не сами значения, а ссылки на них.</p>
3
<p>При этом списки сами тоже передаются по ссылкам. Чтобы убедиться в этом, создадим несколько переменных, содержащих один список, и посмотрим, как они меняются:</p>
3
<p>При этом списки сами тоже передаются по ссылкам. Чтобы убедиться в этом, создадим несколько переменных, содержащих один список, и посмотрим, как они меняются:</p>
4
<p>В примере выше мы создаем новую переменную items2 и записываем в нее ссылку на переменную items. Теперь две переменные ссылаются на один и тот же список. А значит изменив список в любой из переменных, он поменяется и для другой.</p>
4
<p>В примере выше мы создаем новую переменную items2 и записываем в нее ссылку на переменную items. Теперь две переменные ссылаются на один и тот же список. А значит изменив список в любой из переменных, он поменяется и для другой.</p>
5
<h2>Ссылки</h2>
5
<h2>Ссылки</h2>
6
<p>Что же вообще такое "ссылки"? Ссылка это уникальный идентификатор объекта, условный адрес в виртуальной памяти интерпретатора, по которому хранится значение переменной. Получить этот адрес можно функцией id()</p>
6
<p>Что же вообще такое "ссылки"? Ссылка это уникальный идентификатор объекта, условный адрес в виртуальной памяти интерпретатора, по которому хранится значение переменной. Получить этот адрес можно функцией id()</p>
7
<p>Идентификатор - это обычное число. Но у каждого объекта свой уникальный идентификатор. Поэтому идентификаторы удобно использовать, чтобы отслеживать передачи ссылок на объект между разными участками кода - идентификатор объекта будет одним и тем же, по какой бы ссылке мы к объекту ни обращались:</p>
7
<p>Идентификатор - это обычное число. Но у каждого объекта свой уникальный идентификатор. Поэтому идентификаторы удобно использовать, чтобы отслеживать передачи ссылок на объект между разными участками кода - идентификатор объекта будет одним и тем же, по какой бы ссылке мы к объекту ни обращались:</p>
8
<p>Когда мы создаем переменную и записываем в нее значение, то мы как бы даем имя ссылке. Далее, мы присваиваем одну переменную другой, и даем еще одно, новое имя для этой же ссылки. Поэтому id(a) и id(b) возвращают одинаковый результат.</p>
8
<p>Когда мы создаем переменную и записываем в нее значение, то мы как бы даем имя ссылке. Далее, мы присваиваем одну переменную другой, и даем еще одно, новое имя для этой же ссылки. Поэтому id(a) и id(b) возвращают одинаковый результат.</p>
9
<p>Оператор is проверяет равенство идентификаторов своих операндов. В этом примере обе переменные ссылаются на один объект, поэтому проверка a is b дает True.</p>
9
<p>Оператор is проверяет равенство идентификаторов своих операндов. В этом примере обе переменные ссылаются на один объект, поэтому проверка a is b дает True.</p>
10
<p>Проверкой is в Python пользуются, когда мы имеем дело с так называемыми объектами-одиночками. Самые известные одиночки в Python, это True, False и None. Поэтому проверка на равенство None обычно пишется так:</p>
10
<p>Проверкой is в Python пользуются, когда мы имеем дело с так называемыми объектами-одиночками. Самые известные одиночки в Python, это True, False и None. Поэтому проверка на равенство None обычно пишется так:</p>
11
<h2>Сравнение списков</h2>
11
<h2>Сравнение списков</h2>
12
<p>Оператор == сравнивает списки, и любые другие объекты, по значению. То есть два списка будут равны, если имеют одинаковые значения:</p>
12
<p>Оператор == сравнивает списки, и любые другие объекты, по значению. То есть два списка будут равны, если имеют одинаковые значения:</p>
13
<p>Списки также можно сравнивать и по ссылке.</p>
13
<p>Списки также можно сравнивать и по ссылке.</p>
14
<p>В этом примере, хоть списки и содержат одинаковые значения, но каждый список ссылается на свой адрес в виртуальной памяти.</p>
14
<p>В этом примере, хоть списки и содержат одинаковые значения, но каждый список ссылается на свой адрес в виртуальной памяти.</p>
15
<h2>Проектирование функций</h2>
15
<h2>Проектирование функций</h2>
16
<p>Если передать список в какую-то функцию, которая его изменяет, то список тоже изменится. Ведь в функцию передается именно ссылка на список. Посмотрите на пример:</p>
16
<p>Если передать список в какую-то функцию, которая его изменяет, то список тоже изменится. Ведь в функцию передается именно ссылка на список. Посмотрите на пример:</p>
17
<p>Проектируя функции, работающие со списками, есть два пути: менять исходный список или формировать внутри новый и возвращать его наружу. Какой лучше? В подавляющем большинстве случаев стоит предпочитать второй. Это безопасно. Функции, возвращающие новые значения, удобнее в работе, а поведение программы становится в целом более предсказуемым, так как отсутствуют неконтролируемые изменения данных.</p>
17
<p>Проектируя функции, работающие со списками, есть два пути: менять исходный список или формировать внутри новый и возвращать его наружу. Какой лучше? В подавляющем большинстве случаев стоит предпочитать второй. Это безопасно. Функции, возвращающие новые значения, удобнее в работе, а поведение программы становится в целом более предсказуемым, так как отсутствуют неконтролируемые изменения данных.</p>
18
<p>Изменение списка может повлечь за собой неожиданные эффекты. Представьте себе функцию last(), которая извлекает последний элемент из списка. Она могла бы быть написана так:</p>
18
<p>Изменение списка может повлечь за собой неожиданные эффекты. Представьте себе функцию last(), которая извлекает последний элемент из списка. Она могла бы быть написана так:</p>
19
<p>Где-то в коде вы просто хотели посмотреть последний элемент. А в дополнение к этому, функция для извлечения этого элемента взяла и удалила его оттуда. Это поведение очень неожиданно для подобной функции. Оно противоречит большому количеству принципов построения хорошего кода (например "Command-query separation", этот принцип рассматривается в курсе по функциям). Правильная реализация данной функции выглядит так:</p>
19
<p>Где-то в коде вы просто хотели посмотреть последний элемент. А в дополнение к этому, функция для извлечения этого элемента взяла и удалила его оттуда. Это поведение очень неожиданно для подобной функции. Оно противоречит большому количеству принципов построения хорошего кода (например "Command-query separation", этот принцип рассматривается в курсе по функциям). Правильная реализация данной функции выглядит так:</p>
20
<p>В каких же случаях стоит менять сам список? Есть ровно одна причина, по которой так делают - производительность. Именно поэтому некоторые встроенные методы списков меняют их, например reverse() или sort():</p>
20
<p>В каких же случаях стоит менять сам список? Есть ровно одна причина, по которой так делают - производительность. Именно поэтому некоторые встроенные методы списков меняют их, например reverse() или sort():</p>
21
<h2>Копирование списков</h2>
21
<h2>Копирование списков</h2>
22
<p>У списка нет встроенных методов или функций, которые его изменяют, но возвращают новый, не трогая старый. Чтобы изменить список, не затрагивая изначальный, его нужно скопировать.</p>
22
<p>У списка нет встроенных методов или функций, которые его изменяют, но возвращают новый, не трогая старый. Чтобы изменить список, не затрагивая изначальный, его нужно скопировать.</p>
23
<p>Несмотря на то, что подход, меняющий списки напрямую, сложнее в отладке, его используют в некоторых языках для увеличения эффективности работы. Если список достаточно большой, то полное копирование окажется дорогой операцией. В реальной жизни (веб-разработчика) это почти никогда не является проблемой, но знать об этом полезно.</p>
23
<p>Несмотря на то, что подход, меняющий списки напрямую, сложнее в отладке, его используют в некоторых языках для увеличения эффективности работы. Если список достаточно большой, то полное копирование окажется дорогой операцией. В реальной жизни (веб-разработчика) это почти никогда не является проблемой, но знать об этом полезно.</p>
24
<h2>Выводы</h2>
24
<h2>Выводы</h2>
25
<p>Все типы данных в Python передаются по ссылкам. Списки содержат коллекцию не значений, а ссылок.</p>
25
<p>Все типы данных в Python передаются по ссылкам. Списки содержат коллекцию не значений, а ссылок.</p>
26
<p>При передаче списка в функцию передается ссылка на него. Изменение списка внутри функции повлияет на оригинал. Предпочтительнее возвращать новый список из функции, чтобы избежать неожиданных изменений.</p>
26
<p>При передаче списка в функцию передается ссылка на него. Изменение списка внутри функции повлияет на оригинал. Предпочтительнее возвращать новый список из функции, чтобы избежать неожиданных изменений.</p>