Аргументы по ссылке python

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

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

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

a = [0] * 3 s = 'a' * 2 print(a, s) # -> [0, 0, 0], 'aa' 

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

a = [0] b = a b[0] = 1 print(a, b) # -> [1], [1] 

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

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

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

b = a * 2 b[0] = 2 print(a, b) # -> [1], [2, 1] 

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

row = [0] * 2 matrix = [row] * 2 print(matrix) # -> [[0, 0], [0, 0]] matrix[0][0] = 1 print(matrix) # -> [[1, 0], [1, 0]] 

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

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

a = [0] a += (1,) a += a += "ab" a += print(a) # -> [0, 1, 2, 'a', 'b', 1] Заметьте, что строка вставилась посимвольно # ведь именно так работает строковый итератор 

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

def inc(a): a += 1 return a a = 5 print(inc(a)) print(a) # -> 5 

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

def appended(a): a += [1] return a a = [5] print(appended(a)) # -> [5, 1] print(a) # -> [5, 1] 

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

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

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

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

a = [1, 2, 3, 4, 5] def rev(l): l.reverse() return l l = a print(a, l) # -> [1, 2, 3, 4, 5], [1, 2, 3, 4, 5] l = rev(l) print(a, l) # -> [5, 4, 3, 2, 1], [5, 4, 3, 2, 1] 

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

def change(): global a a += 1 a = 5 change() print(a) 

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

def func(a, b): return a + 1, b + 1 

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

def private(value=None): def getter(): return value def setter(v): nonlocal value value = v return getter, setter vget, vset = private(42) print(vget()) # -> 42 vset(0) print(vget()) # -> 0 

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

def private(value=None): def getter(): return value def setter(v): nonlocal value value = v return getter, setter class Person: def __init__(self, name): self.getid, self.setid = private(name) adam = Person("adam") print(adam.getid()) print(adam.setid("john")) print(adam.getid()) print(dir(adam)) 

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

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

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

class Person(): def __getattr__(self, item): print("__getattr__") if item == "name": return "john" raise AttributeError def __getattribute__(self, item): print("__getattribute__") raise AttributeError person = Person() print(person.name) # -> __getattribute__ # -> __getattr__ # -> john 

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

 e = 42 try: 1 / 0 except Exception as e: pass print(e) # -> NameError: name 'e' is not defined 

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

 . print(e) # -> float division by zero 

Источник

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

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

  1. Определение передачи по ссылке в функции Python
  2. Пример передачи по ссылке в Python
  3. Объяснение

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

Определение передачи по ссылке в функции 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.

Сопутствующая статья — Python Function

Источник

Передавать по значению / ссылке и передавать по объектной ссылке в Python? — Подробное объяснение

Готовитесь ли вы к предстоящему собеседованию или в настоящее время работаете разработчиком в компании, эта основная концепция передачи ценностей должна быть известна каждому программисту. Если вы не знаете об этой концепции или путаетесь каждый раз, когда интервьюер задает этот вопрос, я здесь с подробным руководством / объяснением.

Итак, позвольте мне прояснить одну вещь в самом запуске. Модель передачи аргументов Python не является ни «передачей по значению», ни «передачей по ссылке», а «передачей по ссылке на объект».

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

Что такое передача по ссылке?

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

Результат: все операции, выполняемые с этой ссылкой, будут напрямую влиять на переменную, к которой она относится.

Передавать по значению

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

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

Что такое передача объекта по ссылке?

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

Слишком сложно понять? Не стоит беспокоиться! Позвольте мне объяснить в терминах непрофессионала!

  1. В Python переменные не передаются по ссылке или по значению
  2. Вместо этого передается имя (также называемое ссылкой на объект), если базовый объект является изменяемым, тогда модификации объекта сохранятся.
  3. Если базовый объект неизменен, изменения в переменной не сохраняются.

Надеюсь, вы теперь поняли, что есть некоторые небольшие изменения в плане передачи аргументов, когда мы говорим на Python.

Источник

Читайте также:  HTML Document
Оцените статью