Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[译] [303] 函数的角色 #38

Open
cssmagic opened this issue Mar 11, 2024 · 0 comments
Open

[译] [303] 函数的角色 #38

cssmagic opened this issue Mar 11, 2024 · 0 comments

Comments

@cssmagic
Copy link
Owner

cssmagic commented Mar 11, 2024

3.3 Roles of functions

3.3 函数的角色

Functions are used in many different roles in programming. At a high level, programs are 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 code in the following listing. 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.

来看一个例子,我们会用到代码清单 3.1。这段代码出自我们之手,并非由 Copilot 生成。除非是用于教学,否则没人会对编写这样的代码感兴趣。它唯一目的是为了展示函数调用的工作机制。

Listing 3.1 Python code to demonstrate how Python handles function calls
代码清单 3.1 一段代码演示 Python 如何处理函数调用
def funct1():
    print("there")
    funct2()
    print("friend")
    funct3()
    print("")

def funct2():
    print("my")

def funct3():
    print(".")

def funct4():
    print("well")

print("Hi")       #1
funct1()
print("I'm")
funct4()
funct3()
print("")
print("Bye.")
原文 译文 备注
This is the start of the program. We’ll call this “main” after the main function in other languages. 这是程序运行的起点。我们将其称为“main”,以便与其他语言中的 main 函数相对应。

If we ran this program, the output would be (we’ll explain why after):

假如我们执行这段代码,它会产生如下输出结果(具体原因稍后解释):

Hi
there
my
friend
.

I'm
well
.

Bye.

In figure 3.2, we provide 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 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 start of that function, which is the statement: print("there"). The next line of funct1 calls funct2, so the program will execute the first line of funct2: print("my"). What gets 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.) You may be curious why it goes to the next line after the call to funct2 rather than back to the call of funct2. The problem 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 are called.

程序执行将从 Python 代码中首个非函数语句(print("Hi"))开始。Python 并没有严格定义 main 函数,但为了讲解方便,我们将这段代码中位于函数定义后的第一个代码块称为 main。代码按顺序执行,除非遇到需要执行别处代码的命令。执行了 print("Hi") 后,程序将执行 funct1()funct1 函数被调用后,执行点转移到该函数的起始语句 print("there")。接着,funct1 调用 funct2,程序便执行 funct2 函数的第一行 print("my")。当 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 which prints a period (.) and then returns back to its caller.

我们继续往下看,接下来执行的代码行将是打印 “friend”的那一行。紧接着,代码调用了 funct3 函数,输出了一个句点(.),然后返回到调用它的函数。

So, we’re back in funct1, on the line print(""). Printing an empty piece of text 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 接着打印 “I'm”,然后调用 funct4 函数。

  • funct4 prints well and then returns to main where the next line of code calls funct3.

  • funct4 打印 “well” 然后返回到 main,接下来 main 中的下一行代码调用 funct3

  • funct3 prints a period (.) and then returns to main. Notice that funct3 was called both by funct1 and by main, but that’s okay because functions remember how to return 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。值得注意的是,funct1main 都调用了 funct3,这并无不妥,因为函数总是知道如何返回到最初调用它的函数。事实上,一个函数被多个其他函数调用,正说明了这个函数设计得好,因为它具有很好的可复用性。

  • After funct3 returns to main, it will print "" which causes a new line to be started, and then it prints the word Bye.

  • funct3 返回到 main 之后,随后会打印一个空字符串,这将创建新的一行,最后打印出单词 “Bye.”。

Figure 3.2 Flow of function execution in our example from listing 3.1
图 3.2 代码清单 3.1 中函数调用顺序的流程图

原文 译文 备注
Program starts executing here 程序从这里开始执行

That was a long example, but we provided it to 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 function’s 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 becomes this type of coordinating function. Others may call helper function(s) and 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.

某些函数只是单纯地调用一堆其他函数,自身却不执行任何特定任务。我们的示例中并未包含这类函数。不过,如果你拿掉了 funct1 中的三条打印语句,它就会转变为这种协调性质的函数。还有一些函数可能会先调用一些辅助函数,然后自己执行一些任务。funct1 就是一个典型的例子,它既调用了其他函数,也完成了自己的工作。

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 the function calls as a big tree, these functions are the leaves of the tree because 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.

还有一些函数是独立的,不依赖于其他函数(除非是Python内置的函数)来提供帮助——我们将这类函数称作“叶子”函数。为何称之为叶子?把函数调用想象成一棵枝繁叶茂的大树,这些函数就像是树的叶片,它们不会产生更多的分支。funct2funct3funct4 在本例中便是典型的叶子函数。本章将主要专注于叶子函数的探讨,但后续章节里,你将看到更多类型函数的身影。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant