- Изменяемые и неизменяемый типы объектов#
- Разделяемый ссылки#
- Разделяемые ссылки на неизменяемый объект#
- Что вы не знали и передаче параметров в функции
- Передача параметров в других языках
- Использует ли Python модель передачи по значению?
- Использует ли Python передачу по ссылке?
- Объекты в Python
- Изменяемые и неизменяемые объекты
- Переменные и их имя
- В Python используется передача параметров через присваивание
- Передача по ссылке в Python
- Определение передачи по ссылке в функции Python
- Пример передачи по ссылке в Python
- Объяснение
- Сопутствующая статья — Python Function
Изменяемые и неизменяемый типы объектов#
Программисту C/C++ может показаться, что во второй строке увеличивается на 1 значение, хранящееся в созданном на первой строке целочисленном объекте. На самом деле это не так: создаётся новый объект, хранящий результат вычисления выражения a + 1 , а затем имя a связывается с этим новым объектом. Чтобы продемонстрировать это, напечатаем идентификатор объекта до и после увеличения на 1.
a = 0 print(a, id(a)) a += 1 print(a, id(a))
0 2835673868560 1 2835673868592
Видим, что идентификатор меняет свое значение, а значит имя a ссылается на разные объекты до и после инструкции a += 1 .
В python все типы объектов можно разделить на два вида: изменяемые ( mutable ) и неизменяемые ( immutable ).
- Значение, хранящееся в объекте неизменяемого типа, невозможно изменить никакими способами. Единственный способ получить объект такого типа с другим значением — создать новый объект с нужным значением.
- Значение, хранящееся в объекте изменяемого типа, можно изменить не создавая новый объект. Изменения объекта возможно за счет вызова его методов или применения к нему операторов.
Все встроенные числовые типы ( bool , int , float , complex , ( decimal , fractions , которые также присутствуют в стандартной библиотеке, но обсуждаться здесь не будут)) являются неизменяемыми. Единственный изменяемый тип объектов, с которым мы уже сталкивались — list . Продемонстрируем его изменяемость.
Оператор “ += ” определен и для списков, только с другим эффектом: он расширяет список слева от него, элементами итерируемого объекта справа.
l = [42] print(l, id(l)) l += "abc" print(l, id(l))
[42] 1384847112704 [42, 'a', 'b', 'c'] 1384847112704
Для неизменяемого объекта a выражение a += b эквивалентно выражению a = a + b .
Разделяемый ссылки#
Изменяемость и неизменяемость играет наибольшую роль в случае, когда несколько имен ссылаются на один и тот же объект.
Разделяемые ссылки на неизменяемый объект#
Создадим две ссылки a и b на один и тот же объект целочисленного типа.
Во второй строке создаётся имя b и оно связывается с объектом, на которое указывает имя a . Убедиться, что имена указывают на один и тот же объект, можно сравнив их адреса ( id(a) == id(b) ). В python помимо оператора сравнения на равенство “ == ”, ещё есть оператор сравнения на идентичность is , который по сути дела сравнивает ссылки на объекты.
Сравнение на идентичность — более сильная концепция, чем сравнение на равенство: если объекты по ссылками идентичны (один и тот же объект, никак иначе), то они гарантировано равны, но не наоборот, равные объекты могут являться разными сущностями.
Что вы не знали и передаче параметров в функции
В Python при вызове функции используется передача параметров по ссылке или по значению? Сегодня мы попытаемся разобраться. В этой статье вы узнаете: Python не использует модели передачи по ссылке и по значению, а применяет передачу параметров через присваивание; о характеристиках объектов; разницу между изменяемыми(mutable) и неизменяемыми (immutable) объектами.
Передача параметров в других языках
Многие языки программирования предлагают две модели передачи параметров в функции/процедуры:
И то, какую модель использует язык программирования, важно знать, поскольку за эффективность кода отвечает программист лично. А теперь попробуем разобраться, какую модель использует язык Python.
Использует ли Python модель передачи по значению?
При передачи по значению в функцию данные копируются в момент её вызова. Здесь важно понять, что данные (значения) именно копируются, это не те же самые значения. Поэтому в теле функции с ними можно делать всё что угодно, в т.ч. изменять, и это не отразится на исходных данных (тех, которые передали), так как это всего лишь их копии.
В Python не применяется модель передачи по значению, но в некоторых случаях можно видеть нечто похожее. Например, рассмотрим следующий пример:
def foo(x): x = 4 a = 3 foo(a) print(a) # 3
Функция вызывается, но изменения оказанные на переменную a больше не действую после возврата из функции, ведь a всё ещё равна 3. Поэтому может показаться, что используется передача по значению, но это не так. Python не копирует значения параметров при вызове функции. Если мы рассмотрим другую функцию:
def clearly_not_pass_by_value(my_list): my_list[0] = 42 l = [1, 2, 3] clearly_not_pass_by_value(l) print(l) # [42, 2, 3]
— то мы четко видим, что элемент исходного списка l был изменен после вызова функции. Значит ли это, что объект списка использовался один и тот же?
Использует ли Python передачу по ссылке?
При передачи по ссылке в момент вызова функции передаются адреса переменных, причем с адресами работают так, как если бы это была обычная переменная (поэтому не нужно дополнительно проводить разыменование, как это делается в Си). Такая модель подразумевает, что исходные переменные и параметры функции — это одни и те же объекты. Изменяя параметры в теле функции, вы изменяете их и в вызывающем контексте.
Так вот Python не использует и эту модель передачи параметров. Взглянем на следующий код:
def not_pass_by_reference(my_list): my_list = [42, 73, 0] l = [1, 2, 3] not_pass_by_reference(l) print(l) # [1, 2, 3]
Мы предполагаем, что функция должна полностью изменить список, но этого не происходит, он остался прежним. Так какая же модель передачи параметров в функции в используется в Python?
Объекты в Python
В Python всё является объектом. Каждый объект характеризуется следующими характеристиками:
- идентифицирумостью (каждый объект обладает уникальными номером),
- типом (каждый тип обладает своими операциями, которые можно применять),
- содержимое самого объекта.
Эти характеристики можно узнать следующим образом:
>>> id(obj) 2698212637504 >>> type(obj) >>> obj [1, 2, 3]
Эти знания нам пригодятся в дальнейшем.
Изменяемые и неизменяемые объекты
Объекты в Python могут быть изменяемыми (mutable) или неизменяемыми (immutable). Это свойство полностью зависит от типа объекта. Иными словами, не/изменяемость является характеристикой типа, а не конкретных объектов.
Тип является изменяемым, если содержимое объекта может быть изменено без изменений его идентификатора и типа.
Список (list) является изменяемым типом данных. Почему? Потому что списки являются контейнерами: в них можно добавлять данные и из можно удалять данные. Иными словами, их можно спокойно изменять.
Ниже приведен пример того, как содержимое списка меняется, но идентификатор остается тем же самым, что бы мы ни делали.
>>> obj = [] >>> id(obj) 2287844221184 >>> obj.append(0); obj.extend([1, 2, 3]); obj [42, 0, 1, 2, 3] >>> id(obj) 2287844221184 >>> obj.pop(0); obj.pop(0); obj.pop(); obj 42 0 3 [1, 2] >>> id(obj) 2287844221184
С другой стороны, содержимое неизменяемых объектов нельзя изменить. Они существует так, как их инициализировали в первый раз. Строка str является хорошим примером неизменяемого типа.
Вызывая различные методы, призванные как-то модифицировать состояние, объекты с неизменяемым типом что-то возвращают, в отличие от изменяемых. Например, метод списка append ничего не возвращает (он изменяет существующий), а методы строки возвращают новую строку (новый объект):
>>> [].append(0) # Ничего не возвращается >>> "Hello, world!".upper() # Возвращается новая строка 'HELLO, WORLD!"
Другим сигналом неизменяемости объекта является невозможность изменить отдельные его элементы, например, при присваивании через индексы:
>>> obj[0] 'H' >>> obj[0] = "h" Traceback (most recent call last): File "", line 1, in TypeError: 'str' object does not support item assignment
Для справки, в Python встроенные типы:
Переменные и их имя
Ещё необходимо понять, что название переменной — это не то же самое, что и сам объект. Например, имя obj был просто некой меткой, которая была связана с объектом с идентификатором 2287844221184 , типом list и содержимым 1, 2, 3 . Это называется механизмом связывания, о котором мы говорил тут.
Мы вольны связывать и другие метки к этому же самому объекту:
>>> foo = bar = baz = obj >>> id(foo) 2698212637504 >>> id(bar) 2698212637504 >>> id(baz) 2698212637504 >>> id(obj) 2698212637504 # При этом, если изменить объект: >>> obj = 5 >>> id(obj) 94830320197056
Как видим все метки обращаются к одному объекту. В Python даже есть специальный оператор is , который проверяет являются ли два объекты одной сущностью (читай: равны ли их id ).
>>> foo is obj True >>> bar is foo True >>> obj is foo True
Изменяя содержимое через одну переменную, эти изменения можно пронаблюдать через другие, поскольку это один и тот же объект. При этом нужно понимать, объекты, которые имеют тот же тип и содержимое, но не id , не являются одним объектом:
В Python используется передача параметров через присваивание
Теперь мы готовы понять, что за модель передачи параметров используется в Python. При вызове функции каждый параметр связывается с соответствующим объектом, указанным в сигнатуре функции.
Так, если мы передаем неизменяемые параметр (например, int ), то у нас нет возможности хоть как-то его изменить. Каждый раз, когда используется присваивание, то создается новый объект, хоть и имеющий то же самое имя. Взгляните на данный пример:
def foo(bar): bar = 3 return bar a = 5 foo(a)
Вызов функции для неизменяемого типа подразумевает, что используется связывание bar = 5 . Сразу после этого в теле функции осуществляется второе связывание bar = 3 . Но все эти объекты разные. Поэтому при использовании неизменяемых объектов в качестве параметров, их передача осуществляется как будто по схеме передаче значений.
Передача по ссылке в Python
- Определение передачи по ссылке в функции Python
- Пример передачи по ссылке в Python
- Объяснение
В этом руководстве мы продемонстрируем, что вам нужно знать о передаче по ссылке. Ниже мы включили образец программы, следуя которой вы сможете лучше понять эту функцию.
Определение передачи по ссылке в функции Python
Есть много способов определить аргумент в функции в Python; один из этих процессов — передача по ссылке. Слово передать здесь означает передать или передать аргумент функции. Тогда по ссылке означает, что аргумент, переданный функции, в основном упоминается как существующая переменная, а не как отдельная копия этой переменной. В этом методе определения аргумента в функции на переменную, на которую была сделана ссылка, в основном влияет любая выполняемая операция.
Пример передачи по ссылке в Python
def fun(x): x.append('Sam') print("While calling the function:",x) x=['Hello'] print("Before calling the function:",x) fun(x) print("After calling the function:",x)
Before calling the function: ['Hello'] While calling the function: ['Hello', 'Sam'] After calling the function: ['Hello', 'Sam']
Объяснение
В приведенном выше примере функция сначала определяется переменной x . Здесь метод append используется с x для добавления к имени элемента sam . После этого составляется список с использованием элемента x , в котором только один элемент, то есть hello . После печати списка функция, которая была определена изначально, вызывается вместе со своим аргументом x . После вызова функции обратите внимание, что добавленный элемент в самой функции был добавлен в список x .
Этот процесс показывает, как работает передача по ссылке . Функция всегда влияет на изменяемые объекты (объекты, которые могут изменять свое значение или состояние), хранящиеся в переменной, используемой в качестве аргумента функции.
Lakshay Kapoor is a final year B.Tech Computer Science student at Amity University Noida. He is familiar with programming languages and their real-world applications (Python/R/C++). Deeply interested in the area of Data Sciences and Machine Learning.