Основы Python
Переменные в Python передаются по ссылке или по значению?
Короткий ответ
В Python передача аргументов происходит по присваиванию ссылки (pass-by-assignment). Для неизменяемых типов это работает как передача по значению (изменение не влияет на оригинал), а для изменяемых — как передача по ссылке (изменения затрагивают оригинал)
Развернутый ответ
В Python передача аргументов в функции происходит по ссылке на объект, но с важными нюансами, которые часто называют "передачей по присваиванию" (pass by assignment). Вот детальное объяснение:
1. Основной механизм
- Все переменные в Python — это ссылки на объекты
- При передаче в функцию передаётся копия ссылки на объект
- Изменения мутируемых объектов видны снаружи функции
- Изменения имени переменной (переприсваивание) не влияют на оригинал
2. Пример с неизменяемыми (immutable) объектами
def modify_num(x):
x += 10
print("Внутри функции:", x) # 15
num = 5
modify_num(num)
print("Снаружи:", num) # 5 (не изменился)
Для int
, float
, str
, tuple
и других неизменяемых типов: при "изменении" создаётся новый объект, а оригинал остаётся нетронутым.
3. Пример с изменяемыми (mutable) объектами
def modify_list(lst):
lst.append(4)
print("Внутри функции:", lst) # [1, 2, 3, 4]
my_list = [1, 2, 3]
modify_list(my_list)
print("Снаружи:", my_list) # [1, 2, 3, 4] (изменился!)
Для list
, dict
, set
и других изменяемых типов: изменения объекта видны везде, где есть ссылки на него.
4. Переприсваивание vs. изменение объекта
def reassign(lst):
lst = [4, 5, 6] # Создаётся новая локальная ссылка
print("Внутри после переприсваивания:", lst) # [4, 5, 6]
my_list = [1, 2, 3]
reassign(my_list)
print("Снаружи:", my_list) # [1, 2, 3] (не изменился)
Переприсваивание (=
) меняет, на какой объект ссылается переменная, но не изменяет оригинальный объект.
5. Как работает передача аргументов
Действие | Изменяемый объект (list, dict) | Неизменяемый объект (int, str, tuple) |
---|---|---|
Изменение содержимого объекта | Влияет на оригинал | Невозможно (создаётся новый объект) |
Переприсваивание (=) | Не влияет на оригинал | Не влияет на оригинал |
6. Практические следствия
- Для изменяемых объектов используйте
copy()
илиdeepcopy()
, если нужно избежать побочных эффектов:
from copy import deepcopy
def safe_modify(lst):
lst_copy = deepcopy(lst)
lst_copy.append(100)
return lst_copy
- Для возврата нескольких результатов предпочитайте возврат кортежа изменению входных параметров:
def process_data(data):
# Вместо изменения data
return new_data, stats
7. Сравнение с другими языками
- Не похоже на передачу по значению (как в C), так как изменяемые объекты можно модифицировать
- Не похоже на передачу по ссылке (как в PHP), так как переприсваивание не влияет на оригинал
- Ближе всего к передаче указателя по значению (как в Java)
Таким образом, в Python аргументы передаются по ссылке на объект, но сама ссылка передаётся по значению, что объясняет все описанные выше поведения.