HTML Diff
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>