Python inner functions/decorators: 返回内部函数时什么时候应该使用括号?
Python inner functions/decorators: When should I use parentheses when returning an inner function?
我正在学习 Python 装饰器和内部函数,并且对我通过来自 codeacademy.com https://youtu.be/WOHsHaaJ8VQ.
的 YouTube 视频学习的课程有一些疑问
使用内部函数时,有时我必须 return 带括号的函数,有时不带括号。
如果我在不使用装饰器的情况下调用内部函数,我必须在 returning 内部函数时使用括号,否则看起来内部函数是 returned 作为对象(?) .
在 codeacademy.com 和这个 https://www.youtube.com/watch?v=FsAPt_9Bf3U 的 YouTube 视频中,他们调用了不带括号的内部函数,并输出了预期的结果。
如果我使用装饰器调用内部函数,则在 return 内部函数时我必须不使用括号,否则它似乎可以正常工作,但会抛出错误以及其他一些奇怪的结果。
我编写了一些代码来测试不同的变体并输出结果。
您可以在此处查看实时代码:https://trinket.io/python/af1b47658f
# Test 1: The title function returns inner function wrapper without parentheses.
def title(print_name_function):
def wrapper():
print("Professor:")
print_name_function()
return wrapper # Without parentheses
def print_my_name():
print("John")
print('Test 1')
title(print_my_name)
# Results: Nothing is printed.
# Test 2: The title function returns inner function wrapper with parentheses.
def title(print_name_function):
def wrapper():
print("Professor:")
print_name_function()
return wrapper() # With parentheses
def print_my_name():
print("John")
print('Test 2')
title(print_my_name)
# Results: Professor John is printed.
# Test 3: Using a decorator while the title function returns inner function wrapper without parentheses
def title(print_name_function):
def wrapper():
print("Professor:")
print_name_function()
return wrapper # Without parentheses
@title
def print_my_name():
print("John")
print('Test 3')
print_my_name()
# Results: Professor John is printed.
# Test 4: Using a decorator while the title function returns inner function wrapper with parentheses
def title(print_name_function):
def wrapper():
print("Professor:")
print_name_function()
return wrapper() # With parentheses
@title
def print_my_name():
print("John")
print('Test 4')
print_my_name()
# Results: Professor John is printed and the following error is thrown:
'''
Traceback (most recent call last):
File "decorators.py", line 59, in <module>
print_my_name()
TypeError: 'NoneType' object is not callable.
'''
# Additionally, Professor John is printed before 'Test 4' is printed which seems that print_my_name() runs, then print('Test 4') runs.
在上面列出的关于内部的两个视频中 functions/decorators 我发现...
对于内部函数:内部函数 returned 没有使用括号并且 运行 正确。根据我的测试,我必须使用括号才能正确 运行。
对于装饰器:内部函数 returned 没有使用括号并且 运行 正确。根据我的测试, 运行ning 不使用括号是有效的。 运行 括号似乎有效,但输出顺序混淆并引发错误(请参阅我的代码中的测试 4)。
让我们把它分成两部分。
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
.
同样的事情适用于不需要任何参数的函数。
没有括号,你只是在问,"Hey function, you exist?"
加上括号(并且需要 parameters/variables),你是说,"Hey function, do something!"
现在开始第二部分。
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 值是多少?没有 return
语句,所以默认 some_decorator
returns None
。
因此,my_decorator_function被创建,运行,现在有了新的价值。
我们为什么要这种行为?
当我们想要改变输出时,运行多次使用相同的输入使用相同的函数。
例如,也许我想要一个函数,每隔一次调用一次 returns "Go Left",或者每调用 5 次函数一次 "Go Right"。
如果我想用一个有多个变量的函数来做这件事,那很简单!只需将其传入并检查 if num_times == whatever_int
.
但生活并不那么轻松 - 有时其他人已经编写了更简单的函数,并且只允许一个变量,因为它更通用。或者它可能太复杂了,我们需要很长时间才能弄清楚这个函数是如何工作的(而且我们通常不想违反抽象障碍)。在这些情况下,我们需要调整它们的功能以适应我们的需要。
我鼓励您阅读更多关于 Currying 的内容,因为这也将帮助您了解其他用途。
我正在学习 Python 装饰器和内部函数,并且对我通过来自 codeacademy.com https://youtu.be/WOHsHaaJ8VQ.
的 YouTube 视频学习的课程有一些疑问使用内部函数时,有时我必须 return 带括号的函数,有时不带括号。
如果我在不使用装饰器的情况下调用内部函数,我必须在 returning 内部函数时使用括号,否则看起来内部函数是 returned 作为对象(?) . 在 codeacademy.com 和这个 https://www.youtube.com/watch?v=FsAPt_9Bf3U 的 YouTube 视频中,他们调用了不带括号的内部函数,并输出了预期的结果。
如果我使用装饰器调用内部函数,则在 return 内部函数时我必须不使用括号,否则它似乎可以正常工作,但会抛出错误以及其他一些奇怪的结果。
我编写了一些代码来测试不同的变体并输出结果。 您可以在此处查看实时代码:https://trinket.io/python/af1b47658f
# Test 1: The title function returns inner function wrapper without parentheses.
def title(print_name_function):
def wrapper():
print("Professor:")
print_name_function()
return wrapper # Without parentheses
def print_my_name():
print("John")
print('Test 1')
title(print_my_name)
# Results: Nothing is printed.
# Test 2: The title function returns inner function wrapper with parentheses.
def title(print_name_function):
def wrapper():
print("Professor:")
print_name_function()
return wrapper() # With parentheses
def print_my_name():
print("John")
print('Test 2')
title(print_my_name)
# Results: Professor John is printed.
# Test 3: Using a decorator while the title function returns inner function wrapper without parentheses
def title(print_name_function):
def wrapper():
print("Professor:")
print_name_function()
return wrapper # Without parentheses
@title
def print_my_name():
print("John")
print('Test 3')
print_my_name()
# Results: Professor John is printed.
# Test 4: Using a decorator while the title function returns inner function wrapper with parentheses
def title(print_name_function):
def wrapper():
print("Professor:")
print_name_function()
return wrapper() # With parentheses
@title
def print_my_name():
print("John")
print('Test 4')
print_my_name()
# Results: Professor John is printed and the following error is thrown:
'''
Traceback (most recent call last):
File "decorators.py", line 59, in <module>
print_my_name()
TypeError: 'NoneType' object is not callable.
'''
# Additionally, Professor John is printed before 'Test 4' is printed which seems that print_my_name() runs, then print('Test 4') runs.
在上面列出的关于内部的两个视频中 functions/decorators 我发现...
对于内部函数:内部函数 returned 没有使用括号并且 运行 正确。根据我的测试,我必须使用括号才能正确 运行。
对于装饰器:内部函数 returned 没有使用括号并且 运行 正确。根据我的测试, 运行ning 不使用括号是有效的。 运行 括号似乎有效,但输出顺序混淆并引发错误(请参阅我的代码中的测试 4)。
让我们把它分成两部分。
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
.
同样的事情适用于不需要任何参数的函数。
没有括号,你只是在问,"Hey function, you exist?"
加上括号(并且需要 parameters/variables),你是说,"Hey function, do something!"
现在开始第二部分。
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 值是多少?没有 return
语句,所以默认 some_decorator
returns None
。
因此,my_decorator_function被创建,运行,现在有了新的价值。
我们为什么要这种行为?
当我们想要改变输出时,运行多次使用相同的输入使用相同的函数。
例如,也许我想要一个函数,每隔一次调用一次 returns "Go Left",或者每调用 5 次函数一次 "Go Right"。
如果我想用一个有多个变量的函数来做这件事,那很简单!只需将其传入并检查 if num_times == whatever_int
.
但生活并不那么轻松 - 有时其他人已经编写了更简单的函数,并且只允许一个变量,因为它更通用。或者它可能太复杂了,我们需要很长时间才能弄清楚这个函数是如何工作的(而且我们通常不想违反抽象障碍)。在这些情况下,我们需要调整它们的功能以适应我们的需要。
我鼓励您阅读更多关于 Currying 的内容,因为这也将帮助您了解其他用途。