В чем разница между вызовом функции и самой функцией в Python
Что проверяют
Понимаете ли вы, что функция в Python это объект, а скобки это операция вызова над ним. На этом держатся колбэки, декораторы и key= в сортировке. Следом часто спрашивают, что будет, если передать handler() вместо handler, или показывают код с декоратором.
Как отвечать
defэто исполняемая инструкция: дойдя до неё, интерпретатор создаёт объект типаfunctionи связывает его с именем. Тело при этом не выполняется;- имя без скобок: ссылка на объект. Его можно положить в переменную или список, передать аргументом, вернуть из другой функции.
print(greet)покажет<function greet at 0x...>, у объекта есть__name__,__defaults__,__code__; - вызов
greet("Анна"): создаётся новый фрейм, параметры связываются с аргументами, выполняется тело, а значением выражения становится то, что вернулreturn, илиNone; - проверка:
callable(obj)скажет, можно ли объект вызвать. Вызываемы не только функции, но и классы, методы, объекты с__call__.
Практические примеры: sorted(users, key=len) передаёт саму функцию, и sorted вызовет её для каждого элемента. threading.Thread(target=work) запустит work в потоке, а target=work() выполнит её сразу в текущем потоке и передаст в новый только результат. Декоратор принимает функцию и возвращает другую функцию, поэтому внутри него пишут return wrapper, а не return wrapper().
Если нужно отложить вызов с аргументами, используют lambda: work(42) или functools.partial(work, 42).
Где спотыкаются
Не знают, что значения по умолчанию вычисляются один раз, при выполнении def. Поэтому def f(items=[]) делит один список между вызовами, а def f(ts=datetime.now()) навсегда запоминает время загрузки модуля.
Забывают скобки у метода: if user.is_active: при is_active в виде метода всегда истинно, потому что связанный метод как объект истинен.
Путают определение с вызовом в декораторах и возвращают результат вызова вместо обёртки, после чего декорированное имя перестаёт быть функцией.