Вопрос 10 из 16

Основы 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 аргументы передаются по ссылке на объект, но сама ссылка передаётся по значению, что объясняет все описанные выше поведения.