You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Before we can learn about the details of writing a function, we need some insight into their purpose in software. Functions are small tasks that help accomplish larger tasks, which, in turn, help solve larger tasks, and so forth. You probably already have a lot of intuition about breaking apart large tasks into smaller tasks that you can use in the following example.
Suppose that you’ve found a word search puzzle in the newspaper that you’d like to solve (see figure 3.1 for an example puzzle). In these kinds of puzzles, you’re looking for each word in the word list. The words can be found going from left to right, right to left, top to bottom, or bottom to top.
At a high level, your task is “find all of the words in the word search”. Unfortunately, that description of the task isn’t helpful on its own. It doesn’t tell us what steps we need to carry out to solve the problem.
One thing you might do is say, “OK, finding every word is a big task, but a smaller task is just finding the first word (CAT). Let me work on that first!” This is an example of taking a large task and breaking it into smaller tasks. To solve the entire puzzle, then, you could repeat that smaller task for each word that you need to find.
Now, how would we find an individual word, such as CAT? Even this task can be broken down further to make it easier to accomplish. For example, we could break it into four tasks: search for CAT from left to right, search for CAT from right to left, search for CAT from top to bottom, and search for CAT from bottom to top. Not only are we making simpler and simpler tasks, but we’re also organizing our work into logical pieces. And, most importantly, as we’ll see throughout the chapter, it’s these simpler tasks whose code we’re going to ask Copilot to write and ultimately assemble into our complete programs.
Taking a large problem and dividing it into smaller tasks is called problem decomposition, which is one of the most important skills in software design. We’ve dedicated an entire later chapter to it. For now, what is essential is knowing when a task is too big to ask Copilot to complete. Asking it to make a new video game that’s a combination of Wordscapes meets Wordle is not going to work at all. However, you can get Copilot to write a function that’s important to solve a larger problem; for example, you might have a function that checks whether the word provided by the player is present in a list of valid words.
The origin of the name function goes back to math where functions define the output of something based on an input. For example, if f(x) = x2, we can say that when x is 6, f(x) is 36. As programming functions also have expected output for a particular input, the name is quite apt for programming as well.
函数(Function)这一术语源自数学,它是一种基于输入定义输出的数学概念。举个例子,f(x) = x^2 表示当 x 等于 6 时,f(x) 的结果为 36。同样,在编程中,函数也是根据给定的输入来产生预期的输出,因此“函数”这一称呼在编程领域同样适用。
As software engineers, we also like to think of functions as promises or contracts. If there is a function called “larger” and we’re told that it takes two numbers and gives us the larger of the two, we have faith that when we give the function the numbers 2 and 5, it will return the answer of 5. We don’t need to see how that function works to use it, any more than we need to know how the mechanics of a car works to use the brake pedal. Press the brake, and the car slows down. Give the function two numbers, and it gives us back the larger of the two.
Every function in Python has a function header (also called a signature), which is the first line of code of the function. Given their ubiquitous nature, we’ll want to read and write function headers. The function header describes the name of the function and its inputs. In some other languages, it sometimes includes information about what the output looks like, but in Python, you have to find that elsewhere in the code.
In chapter 2, we wrote # comments to tell Copilot what to do. We can continue to use that approach if we want Copilot to generate a function. For example, we can use comments to ask Copilot to write a function that tells us which of two numbers is biggest:
# write a function that returns the larger of two numbers# input is two numbers# output is the larger of the two numbersdeflarger(num1, num2): #1ifnum1>num2:
returnnum1else:
returnnum2
原文
译文
备注
This line is the function header.
这一行就是函数头。
As with the code in the last chapter, we just wrote the comments to prompt Copilot to give us the code. The function header has three main components: the keyword, which tells Python that this is a function; the name of the function; and the inputs to the function. There’s also a colon at the end of the line—be sure to include that or the code will not be valid Python code. The word def denotes that it is creating (defining) a function. After def is the name of the function; that name should describe the behavior of the function as well as possible. The name of this function is larger. If it’s hard to name a function because it does a bunch of different things, that’s usually a clue that it’s too big of a task for a single function, but more on that later.
What appears in the parentheses of the function declaration is the parameters. Parameters are how you provide information to a function that it needs to run. A function can have any number of parameters, and some functions have no parameters. This function has two parameters named num1 and num2; there are two parameters because it needs to know the two numbers it’s comparing.
There can be only one output of a function; the keyword to look for when determining what the function is outputting is return. Whatever follows return is the output of the function. In this code, either num1 or num2 will be returned. Functions are not required to return anything (e.g., a function that prints a list to the screen has no reason to return anything), so if you don’t see a return statement, it isn’t necessarily a problem because the function may be doing something else (interacting with the user, for example) rather than returning something. Functions must also either return something or not return something: they can’t return something in some cases and nothing in other cases.
Although we had Copilot generate this function using # comments, this approach is actually a lot of work for Copilot. It first must get the header right, including figuring out how many parameters you need. Then it must get the actual code of the function right.
There’s an alternate way to prompt Copilot to write the code for a function that may help it generate code more accurately and may help us better understand exactly what we want our function to do. It involves writing a docstring, and we’ll use docstrings to write functions for the majority of the book.
By writing the header and docstring, you’ll make it easier for Copilot to generate the right code. In the header, you will be the one deciding on the name of the function and will provide the names of each parameter that you want the function to use. After the function header, you’ll provide a docstring that tells Copilot what the function does. Then, just as before, Copilot will generate the code for the function. Because we gave Copilot the function header, it will be able to learn from the header and is less likely to make mistakes.
Here’s what the alternate approach would look like when writing that same larger function:
下面展示如何采用另一种方式来编写我们想要的 larger 函数:
deflarger(num1, num2):
""" #1 num1 and num2 are two numbers. #1 Return the larger of the two numbers. #1 """#1ifnum1>num2:
returnnum1else:
returnnum2
原文
译文
备注
Docstring description of the function
函数内的文档字符串
Notice that we wrote the function header as well as the docstring, and Copilot supplied the body of the function.
请注意,我们不仅编写了函数头,还给出了文档字符串;而 Copilot 负责生成函数的具体内容。
3.1.2 Using a function
3.1.2 使用函数
Once we have a function, how do we use it? Thinking back to our f(x) = x2 analogy, how do we give the function a value of 6 for x so that it returns 36? Let’s see how to do this with code by using that larger function we just wrote.
The way to use a function is to call it. Calling a function means to invoke the function on specific values of parameters. These parameter values are called arguments. Each value in Python has a type, and we need to take care to give values of the proper type. For example, that larger function is expecting two numbers; it might not work as expected if we supply inputs that aren’t numbers. When we call a function, it runs its code and returns its result. We need to capture that result so that we can use it later; otherwise, it will be lost. To capture a result, we use a variable, which is just a name that refers to a value.
Here, we ask Copilot to call the function, store the result in a variable, and then print the result:
接下来,我们要求 Copilot 调用函数,将结果保存到一个变量中,然后将结果打印出来:
# call the larger function with the values 3 and 5# store the result in a variable called result# then print resultresult=larger(3, 5) #1print(result)
原文
译文
备注
Calls the larger function with the values 3 and 5 as inputs and store the result
调用 larger 函数,将 3 和 5 作为参数传入,并将结果保存到变量中
The code correctly calls larger. Notice that it puts the two values we want compared after the opening parenthesis. When the function finishes, it returns a value that we assign to result. Then we print the result. If you run this program, you’ll see that the output 5 gets produced, and that’s because 5 is the larger of the two values that we asked about.
So, when you see those parentheses right after a name, it means there’s a function call. Calling functions as we did here will be important to our workflow with Copilot, particularly in how we test functions to see if they are working properly. We’ll also need to call functions to get work done because functions don’t do anything until we call them.
3.1 Functions
3.1 初识函数
Before we can learn about the details of writing a function, we need some insight into their purpose in software. Functions are small tasks that help accomplish larger tasks, which, in turn, help solve larger tasks, and so forth. You probably already have a lot of intuition about breaking apart large tasks into smaller tasks that you can use in the following example.
在我们探讨编写函数的具体细节之前,首先需要深入理解它们在软件开发中的重要性。函数就像是一系列小任务,它们串联起来共同完成更加宏大的任务,进而解决更为复杂的问题。你或许已经具备将复杂任务拆解为简单子任务的直觉,这将在下面的案例中派上用场:
Suppose that you’ve found a word search puzzle in the newspaper that you’d like to solve (see figure 3.1 for an example puzzle). In these kinds of puzzles, you’re looking for each word in the word list. The words can be found going from left to right, right to left, top to bottom, or bottom to top.
假设某天你发现报纸上有一道单词搜索谜题,正打算挑战一番(比如图 3.1 就是一个示例)。在这类谜题中,你的任务是找出单词列表中的每一个单词。这些单词可能横向从左至右、从右至左,或者纵向从上至下、从下至上地隐藏着。
Figure 3.1 Example word search puzzle
图 3.1 单词搜索谜题的示例
At a high level, your task is “find all of the words in the word search”. Unfortunately, that description of the task isn’t helpful on its own. It doesn’t tell us what steps we need to carry out to solve the problem.
在更宏观的层面,你的任务是“在单词搜索谜题中找出所有单词”。然而,这样的任务描述实际上并不具备指导性。它无法告诉我们应该如何具体操作来解决这一问题。
Try working on the problem right now for a couple minutes. How did you start? How did you break down the overall task to make it more achievable?
我们现在就尝试花几分钟来处理这个问题。你以前是从哪里着手的?你以前是如何将整个任务分解,从而让它更容易完成的?
One thing you might do is say, “OK, finding every word is a big task, but a smaller task is just finding the first word (CAT). Let me work on that first!” This is an example of taking a large task and breaking it into smaller tasks. To solve the entire puzzle, then, you could repeat that smaller task for each word that you need to find.
你可能会这样想:“好吧,找出所有单词确实是个庞大的任务,但首先找出第一个单词 ‘CAT’ 则简单多了。我先从这个开始吧!”这是将庞大任务拆解为小任务的一个实际例子。为了完成整道谜题,你后面只需对每个需要寻找的单词重复这个简化后的小任务即可。
Now, how would we find an individual word, such as CAT? Even this task can be broken down further to make it easier to accomplish. For example, we could break it into four tasks: search for CAT from left to right, search for CAT from right to left, search for CAT from top to bottom, and search for CAT from bottom to top. Not only are we making simpler and simpler tasks, but we’re also organizing our work into logical pieces. And, most importantly, as we’ll see throughout the chapter, it’s these simpler tasks whose code we’re going to ask Copilot to write and ultimately assemble into our complete programs.
那么,我们该如何找出一个特定的单词,例如 “CAT”?其实,这个任务同样可以进一步拆解,以便我们更容易地完成。比如,我们可以将其细化为四个子任务:从左至右查找,从右至左查找,从上至下查找,以及从下至上查找。我们这样做,不仅使得任务变得简单,而且也让我们的工作更有条理。更为关键的是,正如我们在本章里会不断看到的,这些简化后的任务将交给 Copilot 来编写代码并实现对应的功能,最终组合成完整的程序。
Taking a large problem and dividing it into smaller tasks is called problem decomposition, which is one of the most important skills in software design. We’ve dedicated an entire later chapter to it. For now, what is essential is knowing when a task is too big to ask Copilot to complete. Asking it to make a new video game that’s a combination of Wordscapes meets Wordle is not going to work at all. However, you can get Copilot to write a function that’s important to solve a larger problem; for example, you might have a function that checks whether the word provided by the player is present in a list of valid words.
将一个复杂问题拆分成若干小任务,这个过程称为“问题分解”,它是软件设计中极其关键的技能之一。我们将在后续章节里详细探讨这一主题。目前,你最需要了解的是,哪些任务对于Copilot来说过于庞大了。譬如,要求它开发一款全新的、将Wordscapes和Wordle融合在一起的电子游戏是完全行不通的。但是,你可以要求Copilot编写一些关键的函数,从而解决更更大的问题。例如,你可以设计一个函数,用来验证玩家输入的单词是否包含在有效单词的列表中。
Copilot can solve that problem well, and that function would help Copilot get closer to solving the larger problem.
Copilot 可以很好地写出这个函数,而且这个函数在后面还能帮到 Copilot,为解决最终的大问题贡献力量。
3.1.1 The components of a function
3.1.1 函数的组成部分
The origin of the name function goes back to math where functions define the output of something based on an input. For example, if f(x) = x2, we can say that when x is 6, f(x) is 36. As programming functions also have expected output for a particular input, the name is quite apt for programming as well.
函数(Function)这一术语源自数学,它是一种基于输入定义输出的数学概念。举个例子,f(x) = x^2 表示当 x 等于 6 时,f(x) 的结果为 36。同样,在编程中,函数也是根据给定的输入来产生预期的输出,因此“函数”这一称呼在编程领域同样适用。
As software engineers, we also like to think of functions as promises or contracts. If there is a function called “larger” and we’re told that it takes two numbers and gives us the larger of the two, we have faith that when we give the function the numbers 2 and 5, it will return the answer of 5. We don’t need to see how that function works to use it, any more than we need to know how the mechanics of a car works to use the brake pedal. Press the brake, and the car slows down. Give the function two numbers, and it gives us back the larger of the two.
作为软件工程师,我们倾向于将函数视作一种承诺或契约。假设存在一个名为“larger”的函数,它接受两个数字并返回其中较大的一个。我们确信,当我们向这个函数提供数字2和5时,它会返回5作为结果。我们在使用这个函数时,并不必要了解其内部工作原理,这与我们使用汽车刹车踏板而无需了解汽车机械构造是同样的道理。踩下刹车,汽车便会减速。向函数传递两个数字,它便会返回较大的那一个。
Every function in Python has a function header (also called a signature), which is the first line of code of the function. Given their ubiquitous nature, we’ll want to read and write function headers. The function header describes the name of the function and its inputs. In some other languages, it sometimes includes information about what the output looks like, but in Python, you have to find that elsewhere in the code.
在 Python 中,每个函数都拥有一个“函数头”,亦称为“函数签名”,它构成了函数代码的第一行。鉴于函数头无处不在,我们自然需要学会如何阅读和书写它们。函数头详细描述了函数的名称和所需的输入。而在其他一些编程语言中,函数头有时还会包含输出结果的相关信息,但在 Python 中,这些信息需要在代码的其他部分寻找。
In chapter 2, we wrote # comments to tell Copilot what to do. We can continue to use that approach if we want Copilot to generate a function. For example, we can use comments to ask Copilot to write a function that tells us which of two numbers is biggest:
在第 2 章里,我们曾通过
#
注释来告诉 Copilot 该做什么。如果我们期望 Copilot 帮我们生成函数,这种方法仍然适用。举个例子,我们可以在注释中要求 Copilot 编写一个函数,用来比较两个数字并找出较大的那个:As with the code in the last chapter, we just wrote the comments to prompt Copilot to give us the code. The function header has three main components: the keyword, which tells Python that this is a function; the name of the function; and the inputs to the function. There’s also a colon at the end of the line—be sure to include that or the code will not be valid Python code. The word def denotes that it is creating (defining) a function. After def is the name of the function; that name should describe the behavior of the function as well as possible. The name of this function is larger. If it’s hard to name a function because it does a bunch of different things, that’s usually a clue that it’s too big of a task for a single function, but more on that later.
与上一章的代码类似,我们刚才写下的注释是为了引导 Copilot 为我们生成代码。函数头包含三个核心部分:一个关键字,用来告诉 Python 这是一个函数;函数的名称;以及函数所需的输入。请注意函数头的结尾还有一个冒号——我们可不能漏掉它,否则这段代码就不是合法的 Python 函数了。
def
是创建(定义)函数的关键字。def
后面的是函数的名称,这个名称应该尽可能准确地描述函数的功能。比如本例中的函数名叫larger
。如果你在给函数起名时感到困难,往往是因为函数要执行多个不同的操作,这也通常意味着这个任务对于单个函数来说太复杂了,我们稍后会进一步讨论这个问题。What appears in the parentheses of the function declaration is the parameters. Parameters are how you provide information to a function that it needs to run. A function can have any number of parameters, and some functions have no parameters. This function has two parameters named num1 and num2; there are two parameters because it needs to know the two numbers it’s comparing.
函数头在括号内放置的内容称作“参数(Parameter)”。参数是我们向函数传递信息的途径,这些信息是函数在运行时所需要的。一个函数可以声明任意数量的参数,某些函数也可能不需要任何参数。本例中的函数声明了两个参数,分别命名为
num1
和num2
;之所以有两个参数,是因为函数需要知道它进行比较的两个数值分别是什么。There can be only one output of a function; the keyword to look for when determining what the function is outputting is return. Whatever follows return is the output of the function. In this code, either num1 or num2 will be returned. Functions are not required to return anything (e.g., a function that prints a list to the screen has no reason to return anything), so if you don’t see a return statement, it isn’t necessarily a problem because the function may be doing something else (interacting with the user, for example) rather than returning something. Functions must also either return something or not return something: they can’t return something in some cases and nothing in other cases.
函数只能输出一个结果;要判断函数将会返回什么内容,关键是要找到
return
关键字。return
后面的部分即为函数的输出结果。在本例的函数中,返回值可能是num1
,也可能是num2
。函数并不一定要返回结果(例如,一个打印列表到屏幕的函数就无需返回任何内容),因此即使没有看到return
语句,也并不说明代码一定有问题,函数很可能在执行其他操作(例如与用户交互)。但是我们在设计函数时要明确一点:函数要么总是有返回,要么总是不返回,不能在有些条件下有返回而在另一些条件下不返回。Although we had Copilot generate this function using # comments, this approach is actually a lot of work for Copilot. It first must get the header right, including figuring out how many parameters you need. Then it must get the actual code of the function right.
尽管我们通过
#
注释让 Copilot 生成函数的做法成功了,但这个过程对 Copilot 来说还是有些繁重。它首先得精确地编写出函数头,包括确定所需的参数数量;然后,它还得确保生成的函数代码正确无误。There’s an alternate way to prompt Copilot to write the code for a function that may help it generate code more accurately and may help us better understand exactly what we want our function to do. It involves writing a docstring, and we’ll use docstrings to write functions for the majority of the book.
还有另外一种方式可以引导 Copilot 编写函数代码,这种方式不仅能帮助它更精确地生成代码,还能让我们更清楚地理解我们期望函数实现的功能。这种方法就是编写文档字符串,我们将在本书中广泛使用文档字符串来定义函数。
Docstrings explain function behavior
用文档字符串来解释函数的行为
Docstrings are how Python functions are described by programmers. They follow the function header and begin and end with three quotation marks.
文档字符串是程序员用来描述 Python 函数行为的一种方法。它们紧跟在函数头之后,用三个引号来标记开头和结尾。
By writing the header and docstring, you’ll make it easier for Copilot to generate the right code. In the header, you will be the one deciding on the name of the function and will provide the names of each parameter that you want the function to use. After the function header, you’ll provide a docstring that tells Copilot what the function does. Then, just as before, Copilot will generate the code for the function. Because we gave Copilot the function header, it will be able to learn from the header and is less likely to make mistakes.
编写函数头和文档字符串,能让 Copilot 更精准地编写代码。在函数头中,你需要确定函数的名称,并指定你希望函数使用的各个参数的名称。紧随函数头之后,你需要编写一段文档字符串来向 Copilot 阐述函数的功能。之后,Copilot 会像之前一样生成函数的代码。由于我们已经给出了函数头,Copilot 能够基于它进行学习,从而减少出错的几率。
Here’s what the alternate approach would look like when writing that same larger function:
下面展示如何采用另一种方式来编写我们想要的
larger
函数:Notice that we wrote the function header as well as the docstring, and Copilot supplied the body of the function.
请注意,我们不仅编写了函数头,还给出了文档字符串;而 Copilot 负责生成函数的具体内容。
3.1.2 Using a function
3.1.2 使用函数
Once we have a function, how do we use it? Thinking back to our f(x) = x2 analogy, how do we give the function a value of 6 for x so that it returns 36? Let’s see how to do this with code by using that larger function we just wrote.
当我们创建好了函数之后,我们应该如何使用它呢?让我们回想一下之前提到的 f(x) = x^2 这个例子,我们如何设定 x 的值为 6,以便函数返回 36 呢?让我们来看看如何通过代码的方式来使用我们刚刚编写的
larger
函数。The way to use a function is to call it. Calling a function means to invoke the function on specific values of parameters. These parameter values are called arguments. Each value in Python has a type, and we need to take care to give values of the proper type. For example, that larger function is expecting two numbers; it might not work as expected if we supply inputs that aren’t numbers. When we call a function, it runs its code and returns its result. We need to capture that result so that we can use it later; otherwise, it will be lost. To capture a result, we use a variable, which is just a name that refers to a value.
使用一个函数的过程称作“调用”。所谓调用,就是向函数的参数传入特定值来执行函数。这些传入的参数值称作“实参(Argument)”。在 Python 语言中,每个值都具有特定的“类型”,我们必须确保传递的参数具有正确的类型。比如,我们之前编写的
larger
函数需要两个数字作为输入;如果我们传入非数字的值,它可能就不会按预期执行。函数在调用时,会执行其内部代码并返回结果。为了稍后能够使用这个结果,我们必须将其捕获,否则结果就会丢失。要捕获函数返回的结果,我们需要用到“变量”,变量本质上是一个指向值的标识。Here, we ask Copilot to call the function, store the result in a variable, and then print the result:
接下来,我们要求 Copilot 调用函数,将结果保存到一个变量中,然后将结果打印出来:
larger
函数,将 3 和 5 作为参数传入,并将结果保存到变量中The code correctly calls larger. Notice that it puts the two values we want compared after the opening parenthesis. When the function finishes, it returns a value that we assign to result. Then we print the result. If you run this program, you’ll see that the output 5 gets produced, and that’s because 5 is the larger of the two values that we asked about.
这段代码正确地调用了
larger
函数。请注意,进行比较的两个数字需要放在一对圆括号的内部。当函数执行完毕后,它会返回一个值,我们将其赋给result
。然后我们打印出结果。如果你运行这个程序,你会看到输出结果是 5,这是因为在我们询问的两个值中,5 是较大的那个。It’s okay if you aren’t comfortable with all the details here, but what we want you to recognize is when a function is being called, as in
如果你对这些细节还不太熟悉,也没关系,但我们希望你至少能够辨识出哪行代码是在调用一个函数,比如:
The general format for a function call is
函数调用的一般格式是这样的:
So, when you see those parentheses right after a name, it means there’s a function call. Calling functions as we did here will be important to our workflow with Copilot, particularly in how we test functions to see if they are working properly. We’ll also need to call functions to get work done because functions don’t do anything until we call them.
因此,当你看到某个名称后面紧跟着圆括号时,应该能反应过来,这正在进行函数调用。类似上面代码所展示的函数调用,对于我们与 Copilot 的协作流程极为重要,尤其是在我们对函数进行测试、验证它们是否按预期工作时。此外,为了完成工作,我们也需要调用函数,因为函数在我们调用它们之前是不会执行任何操作的。
The text was updated successfully, but these errors were encountered: