Functions are used in many different roles in programming. At a high level, programs are really just functions that (often) call other functions. Critically, all programs, including Python programs, originate with a single function (named main in languages like Java, C, and C++). Python’s main function is essentially the first line of code that isn’t in a function. But if every program starts with a single function and we just told you that trying to solve a large problem with a single function is a mistake, how does that work? Well, main will call other functions which, in turn, will call other functions, and so forth. The code will still execute (mostly) sequentially in each function, so it may start in main, but then move to another function, and so forth.
函数在编程领域内承担着多种多样的角色。简而言之,程序本质上是由一系列函数组成,这些函数通常会调用其他函数。关键的一点是,所有的程序——包括 Python 程序——都是从一个基本的函数开始构建的(在 Java、C 或 C++ 等语言中,这个基本函数被称为 main)。在 Python 中,main 函数实际上就是代码中不属于任何函数的第一行。但是,如果每个程序都是从这样一个单一的函数起步,而我们刚才又提到,试图仅用一个函数来解决复杂问题是错误的,这该如何理解呢?其实,main 函数会调用其他函数,而这些被调用的函数又会继续调用更多的函数,依此类推。代码在每个函数内部大体上还是会顺序执行,因此虽然执行可能始于 main 函数,但之后可能会转移到其他函数,如此循环往复。
As an example, let’s use the following code. We wrote this code, not Copilot, because no one would ever want to write this code for anything useful outside teaching. It’s just for demonstrating how function calls work.
If we were to run this program, this would be the output (we’ll explain why below):
假如我们执行这段代码,它会产生以下的输出结果(具体原因我们会在下文进行解释):
Hi
there
my
friend
.
I'm
well
.
Bye.
In figure 3.2, we are providing a diagram of how the code in listing 3.1 would be executed by the computer. We’ve intentionally provided an example that has many function calls to tie together what we just learned. Again, this is NOT practical code; it’s just for learning purposes. Let’s trace through the code execution together. It may be easier to refer to figure 3.2 than listing 3.1 as you follow along, but either will work.
The program will start execution with the first line in the Python code that isn’t a function ( print("Hi") ). Although Python doesn’t have a main function per-se, we’ll refer to the block of code after the functions as main to help this explanation. Code executes sequentially unless it encounters commands that tell it to execute code somewhere else. So, after executing print("Hi"), it will go to the next line which is the call to funct1: funct1(). The call to funct1 changes where the code is executing to the very start of that function which is the statement: print("there"). The next line of funct1 calls funct2, so this means the program will execute the first line of funct2: print("my"). What gets really interesting is what happens when funct2 finishes. There are no more lines of code to execute, so it automatically moves execution back to the first line following the call to funct2 in funct1. (If the function call is in the middle of another statement, that statement resumes execution, but for this example, the function calls are each on their own line.) If you are curious why it goes to the next line after the call to funct2 rather than back to the call of funct2, the issue is if it returned back to the call to funct2, it would be trapped calling funct2 forever. As a result, functions always return back to the next piece of code to execute (in this example, the next line) after they were called.
Continuing this example, the next line of the code executed will be the line that prints “friend”. The next line calls funct3. funct3 prints a “.” and then returns back to its caller.
So, we’re back in funct1, on the line print(""). Printing an empty piece of text just causes a new line. Now funct1 is finished, so it transfers execution back to the next line in main after it was called. We suspect you are getting the idea by now, so let’s move a bit more quickly:
这样,我们又回到了 funct1 函数里的 print("") 行。输出一个空字符串仅仅会创建一个新的行。funct1 函数已经执行结束,接下来它会将执行权交还给 main 函数中它的调用之后的行。我们推测你现在应该已经理解了这个过程,因此让我们更快地继续:
Main next prints “I'm” and then calls funct4.
main 接着打印“我”,然后执行 funct4 函数。
funct4 prints “well” and then returns back to main where the next line of code calls funct3.
funct4 打印 “well” 然后返回到 main,接下来 main 中的下一行代码调用 funct3。
funct3 prints a “.” and then returns back to main. Notice that funct3 was called both by funct1 and by main, but that’s okay because functions remember how to return back to the function that called them. In fact, having multiple functions calling the same function is a sign that the function being called multiple times is a good function, because of its reuse.
funct3 打印出一个“.”接着回到 main。值得注意的是,funct1 和 main 都调用了 funct3,这并无不妥,因为函数总是知道如何返回到最初调用它的位置。事实上,一个函数被多个其他函数调用,这正说明了这个函数设计得好,因为它具有很好的可复用性。
After funct3 returns to main, it will print a “” which causes a new line to be started, and then it prints the word “Bye.”
Figure 3.2 Flow of function execution in our example from listing 3.1.
图 3.2 展示的是来自清单 3.1 的函数调用流程。
That was a long example, but we provided it to help give you an idea of how functions execute and how programs consist of defining and calling functions. In any software you use, think about the specific tasks that it performs: the programmers probably wrote one or more functions for each one. The button in a text editor that changes the text to bold probably calls a function to change the text to bold. That function might change the editor’s internal idea of the text (the editor likely stores your text in a different format than how you view it) and then it might call another function that updates the user’s (your) view of the text.
We’d also like to use this example to discuss the different roles that functions play. A helper function is a function whose job is to make another functions job easier. In a sense, every function that isn’t “main” is a helper function.
Some functions simply call a bunch of other functions without doing any of their own work. There aren’t any of these in our example. However, if you removed the three print statements from funct1, it would become this type of coordinating function. Others may call helper function(s), then do some work on their own. funct1 is a great example of a function that calls other functions but also does work on its own. And another group of functions stand on their own, without calling other functions (except perhaps functions that already come with Python) for help—we’ll call these functions leaf functions. Why leaf? If you imagine all of the function calls as a big tree, these functions are the leaves of the tree as they have nothing coming out of them. funct2, funct3, and funct4 are all leaf functions in our example. We’re primarily concerned with leaf functions in this chapter, but you’ll see examples of other kinds of functions here and especially in later chapters.
3.3 Roles of functions
3.3 函数的角色
Functions are used in many different roles in programming. At a high level, programs are really just functions that (often) call other functions. Critically, all programs, including Python programs, originate with a single function (named main in languages like Java, C, and C++). Python’s main function is essentially the first line of code that isn’t in a function. But if every program starts with a single function and we just told you that trying to solve a large problem with a single function is a mistake, how does that work? Well, main will call other functions which, in turn, will call other functions, and so forth. The code will still execute (mostly) sequentially in each function, so it may start in main, but then move to another function, and so forth.
函数在编程领域内承担着多种多样的角色。简而言之,程序本质上是由一系列函数组成,这些函数通常会调用其他函数。关键的一点是,所有的程序——包括 Python 程序——都是从一个基本的函数开始构建的(在 Java、C 或 C++ 等语言中,这个基本函数被称为 main)。在 Python 中,main 函数实际上就是代码中不属于任何函数的第一行。但是,如果每个程序都是从这样一个单一的函数起步,而我们刚才又提到,试图仅用一个函数来解决复杂问题是错误的,这该如何理解呢?其实,main 函数会调用其他函数,而这些被调用的函数又会继续调用更多的函数,依此类推。代码在每个函数内部大体上还是会顺序执行,因此虽然执行可能始于 main 函数,但之后可能会转移到其他函数,如此循环往复。
As an example, let’s use the following code. We wrote this code, not Copilot, because no one would ever want to write this code for anything useful outside teaching. It’s just for demonstrating how function calls work.
来看一个例子,这段代码出自我们之手,并非 Copilot。在教学之外,没有人会对编写这样的代码感兴趣。它的唯一目的是为了展示函数调用的工作机制。
If we were to run this program, this would be the output (we’ll explain why below):
假如我们执行这段代码,它会产生以下的输出结果(具体原因我们会在下文进行解释):
In figure 3.2, we are providing a diagram of how the code in listing 3.1 would be executed by the computer. We’ve intentionally provided an example that has many function calls to tie together what we just learned. Again, this is NOT practical code; it’s just for learning purposes. Let’s trace through the code execution together. It may be easier to refer to figure 3.2 than listing 3.1 as you follow along, but either will work.
在图 3.2 里,我们展示了一个图表,用以解释计算机是如何处理清单 3.1 里的代码的。我们有意选用了一个包含众多函数调用的例子,目的是为了巩固我们刚刚学习的知识。请记住,这些代码并无实际应用价值;它们仅供教学之用。现在,让我们一步步跟踪代码的执行过程。在跟随这段解释时,你或许会觉得参考图 3.2 比直接看清单 3.1 要更直观一些,但两种方式都是可行的。
The program will start execution with the first line in the Python code that isn’t a function (
print("Hi")
). Although Python doesn’t have amain
function per-se, we’ll refer to the block of code after the functions asmain
to help this explanation. Code executes sequentially unless it encounters commands that tell it to execute code somewhere else. So, after executingprint("Hi")
, it will go to the next line which is the call to funct1:funct1()
. The call tofunct1
changes where the code is executing to the very start of that function which is the statement:print("there")
. The next line offunct1
callsfunct2
, so this means the program will execute the first line offunct2
:print("my")
. What gets really interesting is what happens whenfunct2
finishes. There are no more lines of code to execute, so it automatically moves execution back to the first line following the call tofunct2
infunct1
. (If the function call is in the middle of another statement, that statement resumes execution, but for this example, the function calls are each on their own line.) If you are curious why it goes to the next line after the call tofunct2
rather than back to the call offunct2
, the issue is if it returned back to the call tofunct2
, it would be trapped callingfunct2
forever. As a result, functions always return back to the next piece of code to execute (in this example, the next line) after they were called.程序执行将从 Python 代码中首个非函数语句(
print("Hi")
)开始。Python 并没有严格定义main
函数,但为了讲解方便,我们将函数定义后的第一个代码块称为main
。代码按顺序执行,除非遇到需要执行别处代码的命令。执行了print("Hi")
后,程序将执行funct1()
。funct1
被调用后,执行点转移到该函数的起始语句print("there")
。接着,funct1
调用funct2
,程序便执行funct2
的首句print("my")
。funct2
执行完毕后,情况变得有趣起来:当funct2
执行完毕,由于没有更多代码,执行点会自动回到funct1
中funct2
调用之后的下一行。(若函数调用位于某个语句的中间,那么调用结束后,该语句的剩余部分将继续执行。不过在本例中,每个函数调用都独占一行。)你可能会问,为什么执行点是跳转到funct2
调用之后的行,而不是回到funct2
被调用的位置。这是因为如果执行点返回到funct2
调用处,程序就会陷入无限循环调用funct2
。因此,函数在被调用后,总是返回到紧接着它们的下一段待执行代码(在这个例子中是紧接着的下一行)。Continuing this example, the next line of the code executed will be the line that prints “friend”. The next line calls
funct3
.funct3
prints a “.” and then returns back to its caller.继续这个示例,接下来执行的代码行将输出“friend”。紧接着,代码调用了
funct3
函数。funct3
函数输出了一个句点“.”,然后返回到调用它的地方。So, we’re back in
funct1
, on the lineprint("")
. Printing an empty piece of text just causes a new line. Nowfunct1
is finished, so it transfers execution back to the next line inmain
after it was called. We suspect you are getting the idea by now, so let’s move a bit more quickly:这样,我们又回到了
funct1
函数里的print("")
行。输出一个空字符串仅仅会创建一个新的行。funct1
函数已经执行结束,接下来它会将执行权交还给main
函数中它的调用之后的行。我们推测你现在应该已经理解了这个过程,因此让我们更快地继续:Main next prints “I'm” and then calls
funct4
.main
接着打印“我”,然后执行funct4
函数。funct4
prints “well” and then returns back tomain
where the next line of code callsfunct3
.funct4
打印 “well” 然后返回到main
,接下来main
中的下一行代码调用funct3
。funct3
prints a “.” and then returns back tomain
. Notice thatfunct3
was called both byfunct1
and bymain
, but that’s okay because functions remember how to return back to the function that called them. In fact, having multiple functions calling the same function is a sign that the function being called multiple times is a good function, because of its reuse.funct3
打印出一个“.”接着回到main
。值得注意的是,funct1
和main
都调用了funct3
,这并无不妥,因为函数总是知道如何返回到最初调用它的位置。事实上,一个函数被多个其他函数调用,这正说明了这个函数设计得好,因为它具有很好的可复用性。After
funct3
returns tomain
, it will print a “” which causes a new line to be started, and then it prints the word “Bye.”一旦
funct3
返回到main
,它会打印一个空字符串,这将导致开始新的一行,然后它会打印单词 “Bye”。That was a long example, but we provided it to help give you an idea of how functions execute and how programs consist of defining and calling functions. In any software you use, think about the specific tasks that it performs: the programmers probably wrote one or more functions for each one. The button in a text editor that changes the text to bold probably calls a function to change the text to bold. That function might change the editor’s internal idea of the text (the editor likely stores your text in a different format than how you view it) and then it might call another function that updates the user’s (your) view of the text.
这个例子虽然篇幅颇长,但我们之所以提供,是为了帮助你更好地理解函数的执行方式,以及程序是如何通过定义和调用函数来构成的。当你使用任何软件时,想想它所执行的具体任务:程序员可能为每项任务编写了一个或多个函数。比如,在文本编辑器中将文字加粗的按钮,很可能是调用了一个函数来实现这一功能。这个函数可能会改变编辑器对文字的内部表示(编辑器存储的文字格式可能与你看到的不同),之后它可能还会调用另一个函数来刷新用户(即你)的文字显示。
We’d also like to use this example to discuss the different roles that functions play. A helper function is a function whose job is to make another functions job easier. In a sense, every function that isn’t “main” is a helper function.
我们也可以借此机会探讨函数扮演的各种角色。所谓的“辅助(helper)”函数,是指那些旨在简化其他函数工作的函数。实际上,除了主程序“main”以外,其他的函数都可以视为辅助函数。
Some functions simply call a bunch of other functions without doing any of their own work. There aren’t any of these in our example. However, if you removed the three print statements from
funct1
, it would become this type of coordinating function. Others may call helper function(s), then do some work on their own.funct1
is a great example of a function that calls other functions but also does work on its own. And another group of functions stand on their own, without calling other functions (except perhaps functions that already come with Python) for help—we’ll call these functions leaf functions. Why leaf? If you imagine all of the function calls as a big tree, these functions are the leaves of the tree as they have nothing coming out of them.funct2
,funct3
, andfunct4
are all leaf functions in our example. We’re primarily concerned with leaf functions in this chapter, but you’ll see examples of other kinds of functions here and especially in later chapters.某些函数单纯地调用众多其他函数,本身却不执行任何特定任务。我们的示例中并未包含这类函数。不过,如果你拿掉了
funct1
中的三条打印语句,它就会转变为这种协调性质的函数。还有一些函数可能会先调用一些助手函数,然后自己执行一些任务。funct1
是一个典型的例子,它既调用了其他函数,也完成了自己的工作。还有一些函数是独立的,不依赖于其他函数(除非是Python内置的函数)来提供帮助——我们将这类函数称作“叶子”函数。为何称之为叶子?把函数调用想象成一棵枝繁叶茂的大树,这些函数就像是树的叶片,它们不会产生更多的分支。funct2
、funct3
和funct4
在本例中便是典型的叶子函数。本章节主要关注叶子函数的探讨,但在本书的其他部分,尤其是后续章节中,你将看到更多其他类型函数的应用实例。