Давайте разберем это на две части.
1) Давайте пока проигнорируем декораторы.
Вы должны использовать скобки, когда хотите вызвать какую-то функцию.
Без скобок функция - это просто имя.
Например:
Вот функция, в которой мы присваиваем ей номер, и мы возвращаем это число плюс 5.
def add_five(x):
return x + 5
Мы видим, что add_five
без скобок - это просто определение функции.Думайте об этом как рецепт.Это на самом деле не торт, а только инструкция о том, как испечь торт.
>>> add_five
<function add_five at 0x10da3ce18>
Теперь мы даем ему ингредиент, и он делает торт:
>>> add_five(1)
6
Давайте сделаемпохожая вещь, но с лучшими именами.
>>> def make_cake(cake_type):
>>> print("Making: " + cake_type + " cake!")
>>> make_cake("carrot")
'Making: carrot cake!'
>>> make_cake
<function make_cake at 0x10da3cf28>
Хорошо, поэтому, когда мы помещаем имя функции без скобок, мы фактически не вызываем функцию, мы просто получаем объявление функции (что-то вроде сертификата рождения функции, который имеет адрес памяти, в этом случае: 0x10da3cf28
.
То же самое относится к функциям, которые не ожидают никаких параметров.
Без скобок вы просто спрашиваете: «Привет, функция, вы существуете?»
С круглыми скобками (и необходимыми параметрами / переменными), выговоря: «Эй, сделай что-нибудь!»
Теперь о второй части.
2) Что делают декораторы?
@ SyntaxVoid имеет отличное объяснение того, что вы делаете.Декораторы - гораздо более сложная вещь, поэтому я остановлюсь на объяснении того, что они делают в этом конкретном контексте.
По сути, ваш декоратор, @<Some Function Name>
определяет функцию для вызова декорированной функции.
def some_decorator(function_that_I_decorated):
print("I'm going to print this, and then call my decorated function!")
function_that_I_decorated()
@some_decorator
def my_decorated_function():
print("Did I do anything?")
Затем мы видим результаты:
>>> def some_decorator(function_that_I_decorated):
... print("I'm going to print this, and then call my decorated function!")
... function_that_I_decorated()
...
>>> @some_decorator
... def my_decorated_function():
... print("Did I do anything?")
...
I'm going to print this, and then call my decorated function!
Did I do anything?
Теперь вот важная часть:
>>> my_decorated_function
>>> my_decorated_function()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
Подождите ... мы не определили my_decorated_function
?
Да, мы определили функцию, но декоратор переназначает имя этой функции чему-то другому.
А именно, my_decorator_function = some_decorator(my_decorator_function)
Сейчасsome_decorator
случается что-то сделать перед вызовом my_decorator_function
.Он печатает некоторые вещи.Но каково возвращаемое значение some_decorator
?Нет оператора return
, поэтому some_decorator
возвращает None
по умолчанию.
Поэтому функция my_decorator_function была создана, запущена и теперь имеет новое значение.
Почему бымы хотим, чтобы это поведение?
Когда мы хотим, чтобы выходной сигнал менялся, при запуске одной и той же функции с одним и тем же входом (входами) несколько раз.
Например, может быть, я хочуфункция, которая возвращает «Go Left» каждый раз, когда она вызывается, или «Go Right» каждые 5 раз, когда вызывается функция.
Если я хочу сделать это с функцией с более чем одной переменной, это легко!Просто передайте его и проверьте if num_times == whatever_int
.
Но жизнь не так проста - иногда у других людей уже написаны функции, которые намного проще и допускают только одну переменную, потому что она более обобщаема.Или, может быть, это настолько сложно, что нам понадобится очень много времени, чтобы понять, как работает эта функция (и мы обычно не хотим нарушать барьеры абстракции).В этих ситуациях нам необходимо адаптировать их функции к нашим потребностям.
Я бы посоветовал вам прочитать больше о Curry , поскольку это поможет вам понять и другие области применения.