Как происходит передача аргументов в функцию в Python
Что проверяют
Понимаете ли вы, что передаётся ссылка на объект, и различаете ли присваивание и изменение.
Как отвечать
В Python нет ни передачи по значению, ни передачи по ссылке в классическом понимании. Передаётся ссылка на объект, причём по значению. Это иногда называют передачей по разделению.
Практически это значит: параметр становится ещё одним именем для того же объекта. Отсюда два разных случая.
Присваивание параметру просто переназначает локальное имя, снаружи ничего не меняется:
def rebind(items):
items = [1, 2, 3] # локальное имя смотрит на новый список
lst = []
rebind(lst)
lst # []Изменение объекта видно снаружи, потому что объект тот же:
def mutate(items):
items.append(1)
lst = []
mutate(lst)
lst # [1]Отсюда наблюдение, которое всё объясняет: неизменяемые типы ведут себя как передача по значению, потому что изменить их на месте нельзя вовсе. Изменяемые ведут себя как передача по ссылке. Но правило при этом одно и то же, различается только природа объекта.
Связанная классическая ловушка это изменяемое значение по умолчанию. Оно вычисляется один раз при определении функции, поэтому один и тот же список разделяется между вызовами и накапливает изменения. Правильно ставить пустое значение и создавать объект внутри.
Про способы передачи стоит добавить: позиционные и именованные аргументы, сбор остальных позиционных и именованных, а также возможность объявить параметры только позиционными или только именованными. Последнее полезно для читаемости: имя параметра при вызове делает смысл булева флага очевидным.
Где спотыкаются
Говорят «по ссылке» и не могут объяснить, почему присваивание не видно снаружи.
Ставят изменяемое значение по умолчанию.
Изменяют переданный список, не предупредив об этом вызывающего.
Считают, что для чисел и строк работает другой механизм передачи.