python - 为什么遇到'return'语句时执行不停止?
问题描述
当我阅读这段代码时:
def factorial(number):
if not isinstance(number, int):
raise TypeError("Sorry. 'number' must be an integer.")
if number < 0:
raise ValueError("Sorry. 'number' must be zero or positive.")
def inner_factorial(number):
if number <= 1:
return 1
return number * inner_factorial(number - 1)
return inner_factorial(number)
我无法理解这部分代码:
def inner_factorial(number):
if number <= 1:
return 1
return number * inner_factorial(number - 1)
return inner_factorial(number)
我的意思是,当 Python 看到语句时,它不会停止代码return
吗?我想知道return number * inner_factorial(number - 1)
代码行是如何工作的。
解决方案
您突出显示的行属于内部功能。如果有帮助,您可以将它们分开考虑,如下所示。
def inner_factorial(number):
if number <= 1:
return 1
return number * inner_factorial(number - 1) # 1
def factorial(number):
if not isinstance(number, int):
raise TypeError("Sorry. 'number' must be an integer.")
if number < 0:
raise ValueError("Sorry. 'number' must be zero or positive.")
return inner_factorial(number) # 2
该factorial
函数仅返回inner_factorial
传入的相同值(第 2 行)。然后,inner_factorial
被调用并返回自身,这意味着它是一个递归调用。inner_factorial
将调用自己,直到number
变得小于或等于1
。
递归是如何工作的?
当我们运行时factorial(4)
,这些值被推送到调用堆栈(调用堆栈是堆栈数据结构,用于存储有关计算机程序的活动子例程的信息。调用堆栈很重要,因为每个任务都可以拥有自己的单独堆栈。这意味着每个被调用的函数可以同时为不同的任务执行不同的事情。另一个优点是调用堆栈自动支持递归调用。)在程序中,将有一个新inner_factorial
函数压入调用堆栈直到inner_factorial
返回1
。要看到这一点,可以在函数的返回语句中使用带有断点的调试器(我使用 PyCharm 的)inner_factorial
并使用单步执行按钮。因此,factorial(4)
我们填充了 4 个新的inner_factorials
。
如果我继续单击 step into 按钮,这些inner_factorials
将被一一删除。(从调用堆栈中弹出,这就是为什么它以与被推入调用堆栈时相反的顺序发生)
另一件事是这种乘法是一次完成还是顺序完成。*
为了测试这一点,我创建了一个函数multiply
来揭示幕后发生的事情,而不是使用乘法。看来乘法是按如下方式完成的:
2x1 → 3x2 → 4x6
. 可以通过运行以下脚本来说明此行为:
import time
def inner_factorial(number):
if number <= 1:
return 1
time.sleep(1)
def multiply(a, b):
print(f"multiplying {a} with {b}.")
time.sleep(1)
return a * b
return multiply(number, inner_factorial(number - 1)) # <- change is in here.
# where multiply (number being popped of the call stack, return a*b)
# multiplying 2 with 1.
# multiplying 3 with 2.
# multiplying 4 with 6.
# 24
inner_factorial(4)
如果我误解任何部分并解释错误,请告诉我。
推荐阅读
- c# - 如何在 Elasticsearch .net 客户端 7.4 中更新文档?
- python - Numpy:从另一个矩阵创建块矩阵的函数,每个块应该包含来自另一个矩阵的相同索引的值
- git - R Studio 和 Git 不会同步
- ruby - 使用 rails 获取桌面中文件的路径
- javascript - 如何在 blob/buffer 的 MIME 类型之间进行转换?
- c# - 难以理解沿局部和全球空间统一的运动
- c++ - 有没有什么东西限制了未来的 C++ 标准引入多个返回值?
- openssl - 使用 OpenSSL CLI 从 x509 证书获取链或 CA 颁发者
- bash - 使用包含单引号的 grep 命令创建别名
- php - Php 不会捕获内容的结果,而只会捕获标题