Что значит объекты передаются по ссылке python

от admin

Интересности и полезности python. Часть 3

В предыдущих частях мы рассмотрели срезы, распаковку\упаковку коллекций и некоторые особенности булевых операций и типов.

В комментариях упоминалась возможность умножения коллекций на скаляр:

Более-менее опытный разработчик на языке python знает, что в нём отсутствует механизм копирования при записи

Что же тогда выведет следующий код?

Python в данном случае работает по принципу наименьшего удивления: в переменной a у нас хранится одна единица, то есть b можно было объявить и как

Поведение в данном случае будет такое же:

Но не всё так просто, python копирует содержимое списка столько раз, на сколько вы его домножили и конструирует новый список. А в списках хранятся ссылки на значения, и если, при копировании таким образом ссылок на неизменяемые типы всё хорошо, то вот с изменяемыми вылезает эффект отсутствия копирования при записи.

Генераторы списков и numpy вам в помощь в данном случае.

Списки можно складывать и даже инкрементировать, при этом справа может находиться любой итератор:

Вопрос с подвохом (для собеседования): в python параметры передаются по ссылке или по значению?

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

В таких языках как C++ есть переменные, хранящиеся на стеке и в динамической памяти. При вызове ф-ции мы помещаем все аргументы на стек, после чего передаём управление функции. Она знает размеры и смещения переменных на стеке, соответственно может их правильно интерпретировать.
При этом у нас есть два варианта: скопировать на стек память переменной или положить ссылку на объект в динамической памяти (или на более высоких уровнях стека).
Очевидно, что при изменении значений на стеке функции, значения в динамической памяти не поменяются, а при изменении области памяти по ссылке, мы модифицируем общую память, соответственно все ссылки на эту же область памяти «увидят» новое значение.

В python отказались от подобного механизма, заменой служит механизм связывания(assignment) имени переменной с объектом, например при создании переменной:

Интерпретатор создаёт объект «john» и «имя» var, а затем связывает объект с данным именем.
При вызове функции, новых объектов не создаётся, вместо этого в её области видимости создаётся имя, которое связывается с существующим объектом.
Но в python есть изменяемые и неизменяемые типы. Ко вторым, например, относятся числа: при арифметических операциях существующие объекты не меняются, а создаётся новый объект, с которым потом связывается существующее имя. Если же со старым объектом после этого не связано ни одного имени, оно будет удалено с помощью механизма подсчёта ссылок.
Если же имя связано с переменной изменяемого типа, то при операциях с ней изменяется память объекта, соответственно все имена, связанные с данной областью памяти «увидят» изменения.

Можно почитать про это в документации, более подробно изложено здесь.

Ещё один пример:

Но что, если мы решили поменять переменную вне функции? В данном случае нам поможет модификатор global:

Замечание: не надо так делать (нет, серьёзно, не используйте глобальные переменные в своих программах, и тем более не в своих). Лучше просто вернуть несколько значений из функции:

Однако, в python присутствует и другая область видимости и соответствующее ключевое слово:

В данном примере, мы создали переменную, которую можно изменить (и чьё значение получить) только через методы, можно использовать подобный механизм и в классах:

Но, пожалуй, лучше будет ограничиться свойствами или определением __getattr__, __setattr__.

Можете даже определить __delattr__.

Ещё одной особенностью python является наличие двух методов для получения атрибута: __getattr__ и __getattribute__.

В чём между ними разница? Первый вызывается лишь, если атрибут в классе не был найден, а второй безусловно. Если в классе объявлены оба, то __getattr__ вызовется, лишь, если явно его вызвать в __getattribute__ или, если __getattribute__ сгенерировал AttributeError.

И на последок пример того, как python вольно обращается с переменными и областями видимости:

Это, кстати, пожалуй единственный пример, когда второй python лучше третьего, потому что он выводит:

Передача списка в функцию: по ссылке или по значению?

при вызове my_function с my_list в качестве аргумента, ожидаемо видим вывод на печать списка из четырех элементов:

и измененный my_list :

Но если сделать так:

то выходит, что по значению:

Как, все таки, изменяемые типы передаются в функцию в качестве аргументов?

В первом примере вы изменяет полученный список, а во втором создаётся новый который никак не связан с my_list

в первом случае my_list и результат функции это один объект, а во втором два разных

Danis's user avatar

В переменной values у вас получается ссылка на переданный список. И когда вы в этот список что-то добавляете внутри функции, то данные добавляются в исходный список, на который указывает переменная.

Однако, если вы присвоите внутри функции переменной values ссылку на новый список, это никак не повлияет на тот список, который был передан в функцию — переменная values существует только внутри функции и после такого присвоения она просто потеряет всякую связь с исходным списком.

Читать:
Как удалить все символы кроме букв python

Это в общем-то так с любыми переменными внутри функции — когда вы им что-то присваиваете, это никак не влияет на те переменные, которые были переданы в функцию. Скорее наоборот тут несколько удивительно, что вы можете менять список, ссылка на который была передана в функцию. Но это именно благодаря тому, что в переменной находится не сам список, а ссылка на него.

Ссылки — Python: Списки

Пока мы работали с неизменяемыми значениями, эти значения передавались в функции и сохранялись в переменных.

С изменяемыми объектами все по-другому. Настало время узнать, что в Python все передается по ссылке. Что же такое ссылка? Разберемся в этом уроке.

Но начнем знакомство со старших братьев ссылки — это адреса и указатели.

Ссылки и управление памятью

Все данные, с которыми работает программа, находятся в оперативной памяти компьютера. Чтобы иметь доступ к некоторому участку памяти, нужно знать адрес этого участка.

В языках с ручным управлением памятью необходимо постоянно следить за тем, что память по адресу выделена и еще не освобождена. В таких языках программист явно запрашивает у операционной системы нужное ему количество памяти.

Операционная система в ответ на запрос выделяет участок в общей оперативной памяти, закрепляет этот блок за попросившим доступ и возвращает указатель, по сути представляющий собой тот самый адрес. Получив указатель, программист может сохранить что-то в выделенную память.

По окончании работы выделенные участки нужно освобождать — сообщать ОС, что память свободна и может быть использована для чего-то другого. Если обратиться по указателю к участку памяти, который еще не выделен или уже освобожден, программа завершится с ошибкой.

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

Как только данные перестают использоваться, память будет освобождена — также автоматически. Таким образом ссылки выполняют ту же роль, что и указатели в упомянутых выше языках. Но пользоваться ссылками всегда безопасно: ссылка не может указывать на память, не готовую к использованию.

Более того, программисту на Python не нужно отдельно получать память и отдельно заполнять ее — данные размещаются в памяти все той же средой исполнения.

Как работают ссылки

Когда мы создаем некое значение, мы получаем от среды исполнения именно ссылку на него. Ссылок на одно и то же значение в любой момент времени может быть сколько угодно. Python экономит усилия и всегда и везде передает любые значения по ссылкам — создает новые ссылки на существующие данные. Даже переменные — это всего лишь имена, привязанные к ссылкам.

И при вызове функции с передачей ей аргументов, передаются не сами значения, а только ссылки на них — по одной новой ссылке на каждое значение. Когда выполнение функции завершится, ненужные ссылки уничтожаются.

Как только исчезает последняя ссылка на некое значение, среда исполнения понимает, что и само значение больше никому не нужно и его можно удалить из памяти, освободив таким образом место. Этим занимается специальный механизм среды исполнения, так называемый счетчик ссылок.

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

Передача по ссылке в Python

Передача по ссылке в Python

В этом руководстве мы продемонстрируем, что вам нужно знать о передаче по ссылке. Ниже мы включили образец программы, следуя которой вы сможете лучше понять эту функцию.

Определение передачи по ссылке в функции Python

Есть много способов определить аргумент в функции в Python; один из этих процессов — передача по ссылке. Слово передать здесь означает передать или передать аргумент функции. Тогда по ссылке означает, что аргумент, переданный функции, в основном упоминается как существующая переменная, а не как отдельная копия этой переменной. В этом методе определения аргумента в функции на переменную, на которую была сделана ссылка, в основном влияет любая выполняемая операция.

Пример передачи по ссылке в Python

Объяснение

В приведенном выше примере функция сначала определяется переменной x . Здесь метод append используется с x для добавления к имени элемента sam . После этого составляется список с использованием элемента x , в котором только один элемент, то есть hello . После печати списка функция, которая была определена изначально, вызывается вместе со своим аргументом x . После вызова функции обратите внимание, что добавленный элемент в самой функции был добавлен в список x .

Этот процесс показывает, как работает передача по ссылке . Функция всегда влияет на изменяемые объекты (объекты, которые могут изменять свое значение или состояние), хранящиеся в переменной, используемой в качестве аргумента функции.

Похожие статьи