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
There’s no clear rule for what makes a good function, but there are some intuitions and recommendations we can share. Make no mistake, though: identifying good functions is a skill that takes time and practice. To help you with this, in this section we’ll outline our recommendations and provide you with some good and bad examples to help build that intuition. Then, in section 3.6, we’ll show you examples of how to write good functions.
Here are some guidelines that we believe will help you see what makes a good function:
下面是一些指导原则,我们相信将有助于你理解怎样设计出一个优秀的函数:
One clear task to perform—A leaf functions, might be something like“compute the volume of a sphere,” “find the largest number in a list,” or “check to see if a list contains a specific value.” Nonleaf functions can achieve broader goals, like “update the game graphics” or “collect and sanitize input from the user.” Nonleaf functions should still have a particular goal in mind but are designed knowing they will likely call other functions to achieve their goal.
Clearly defined behavior—The task “find the largest number in a list” is clearly defined. If I gave you a list of numbers and asked you for the largest number, you know what you should do. In contrast, the task “find the best word in the list” is poorly defined as stated. You need more information: What is the “best” word? Is it the longest, the one that uses the fewest vowels, or the one that doesn’t share any of the same letters as “Leo” or “Dan”? You get the point; subjective tasks aren’t great for computers. Instead, we could write the function “find the word in the list that has the most characters” because what is expected is well defined. Often programmers can’t put all the particulars of a function just in the name, so they fill in the details in the docstring to clarify its use. If you find yourself having to write more than a few sentences to describe the function’s behavior, the task is probably too much for a single function.
Short in number of lines of code—We’ve heard different rules over the years for the length of functions, informed by different company style guidelines. The lengths we’ve heard vary from 12 to 20 lines of Python code as the maximum number of lines. In these rules, the number of lines is being used as a proxy for code complexity, and it’s not a bad general rule of thumb. As programmers ourselves, we both apply similar rules to our code to ensure the complexity doesn’t get out of hand. With Copilot, we can use this as a guide as well. If you ask Copilot for a function and it gives you back 50 lines of code, this probably isn’t a good function name or task, and as we discussed earlier, that many lines of code are likely to have errors anyway.
General value over specific use—A function that returns the number of values in a list that are greater than 1 might be a specific need for a part of your program, but there’s a way to make this better. The function should be rewritten to return the number of values in the list that are greater than another parameter. The new function would work for your use case (give the function 1 for the second parameter) and for any value other than 1. We strive to have functions be as simple but as powerful as possible.
Clear input and output—You generally don’t want a lot of parameters. That doesn’t mean you can’t have a lot of input, though. A single parameter could be a list of items (we’ll talk more about lists soon). It does mean that you want to find ways to keep the number of inputs to a minimum. You can only return one thing, but again, you can return a list so you aren’t as limited as it may appear. But if you find yourself writing a function that sometimes returns a list, sometimes returns a single value, and sometimes returns nothing, that’s probably not a good function.
Print the state of the checkers game—Given a 2D list representing the game board, output the game board to the screen in text.
“打印跳棋游戏的状态” —— 给定一个二维列表代表游戏棋盘,在屏幕上以文本形式输出棋盘状态。
Insert a value in a list—Given a list, a new value, and a location in the list, return a new list that is the old list with the new value inserted at the desired location.
Here are examples of bad leaf functions and our reasons for why they are bad:
以下是一些反面例子,我们也解释了它们不好的原因:
Request a user’s tax information and return the amount they owe this year—Perhaps in some countries this wouldn’t be too bad, but we can’t imagine this as a single function in either the United States or Canada given the complexity of the tax rules!
Identify the largest value in the list and remove that value from the list—This might not seem so bad, but it’s really doing two things. The first is to find the largest value in the list. The second is to remove a value from the list. We’d recommend two leaf functions, one that finds the largest and one that removes the value from the list. However, this might make a good nonleaf function if your program needs to perform this task frequently.
(Thinking of our dataset from chapter 2) Return the names of the quarterbacks with more than 4,000 yards of passing in the dataset—This has too much specificity. Without a doubt, the number 4,000 should be a parameter. But it’d likely be better to make a function that takes as input the position (quarterback, running back), the statistic (passing yards, games played), and the cutoff that we care about (4,000, 8,000) as parameters. This new function provides far more capability than the original, allowing a user to call the function to determine not only the names of particular quarterbacks who threw for more than 4,000 yards but also, for example, running backs who had more than 12 rushing touchdowns.
Determine the best movie of all time—This function is too vague. Best movie by what definition? What movies should be considered? A better version of this might be a function that determines the highest-rated movie by users given at least a minimum number of ratings. This function would likely be part of a larger program where the function would have data from a movie database (say, IMDB) and minimum number of user ratings as inputs. The output of the function would be the highest-rated movie that has at least as many ratings as specified.
3.4 What’s a reasonable task for a function?
3.4 交给函数的合理任务应该是什么样的?
There’s no clear rule for what makes a good function, but there are some intuitions and recommendations we can share. Make no mistake, though: identifying good functions is a skill that takes time and practice. To help you with this, in this section we’ll outline our recommendations and provide you with some good and bad examples to help build that intuition. Then, in section 3.6, we’ll show you examples of how to write good functions.
优秀的函数并没有固定的标准,但我们能提供一些直观的建议和指导。需要明确的是,辨别优秀的函数是一项需要时间积累和实践锻炼的能力。在本节中,我们会简要介绍我们的建议,并给出一些好的与坏的示例,以助于培养这种直觉。接下来,在第 3.6 节中,我们会提供一系列编写优秀函数的实例。
3.4.1 Attributes of good functions
3.4.1 优秀函数的特征
Here are some guidelines that we believe will help you see what makes a good function:
下面是一些指导原则,我们相信将有助于你理解怎样设计出一个优秀的函数:
One clear task to perform—A leaf functions, might be something like“compute the volume of a sphere,” “find the largest number in a list,” or “check to see if a list contains a specific value.” Nonleaf functions can achieve broader goals, like “update the game graphics” or “collect and sanitize input from the user.” Nonleaf functions should still have a particular goal in mind but are designed knowing they will likely call other functions to achieve their goal.
执行一项明确的任务。以叶子函数为例,明确的任务可能是“计算一个球体的体积”、“从列表中找出最大的数字”或是“检查一个列表是否包含某个特定值”。对于非叶子函数来说,它们可能承担着更为广泛的目标,例如“刷新游戏画面”或“接收并净化用户输入”。尽管非叶子函数也有着明确的目标,但其在设计之初就已经考虑到可能会调用其他函数来完成自身的目标。
Clearly defined behavior—The task “find the largest number in a list” is clearly defined. If I gave you a list of numbers and asked you for the largest number, you know what you should do. In contrast, the task “find the best word in the list” is poorly defined as stated. You need more information: What is the “best” word? Is it the longest, the one that uses the fewest vowels, or the one that doesn’t share any of the same letters as “Leo” or “Dan”? You get the point; subjective tasks aren’t great for computers. Instead, we could write the function “find the word in the list that has the most characters” because what is expected is well defined. Often programmers can’t put all the particulars of a function just in the name, so they fill in the details in the docstring to clarify its use. If you find yourself having to write more than a few sentences to describe the function’s behavior, the task is probably too much for a single function.
行为定义明确。比如“在列表中找出最大的数字”这个任务就定义得很明确。假如我给你一组数字,要你找出其中最大的那个,你知道该如何下手。反观“在列表中找出最佳单词”这个任务,就表述得过于模糊了。你需要更多的信息才能开工——什么样的单词算是“最佳”?是最长的,还是使用元音字母最少的,或是与“Leo”和“Dan”没有任何相同字母的单词?你应该明白问题所在了——主观性的任务对计算机来说并不合适。相反,我们可以编写一个函数,其作用是“在列表中找到拥有最多字符的单词”,这样的预期行为就定义得十分明确。通常,程序员无法仅通过函数名就交待清楚函数的所有细节,于是他们会在文档字符串中补充详细信息,以便阐明函数的具体用途。如果你发现自己需要写上好几句话才能描述一个函数的行为,那么这个任务可能对于单个函数来说过于复杂了。
Short in number of lines of code—We’ve heard different rules over the years for the length of functions, informed by different company style guidelines. The lengths we’ve heard vary from 12 to 20 lines of Python code as the maximum number of lines. In these rules, the number of lines is being used as a proxy for code complexity, and it’s not a bad general rule of thumb. As programmers ourselves, we both apply similar rules to our code to ensure the complexity doesn’t get out of hand. With Copilot, we can use this as a guide as well. If you ask Copilot for a function and it gives you back 50 lines of code, this probably isn’t a good function name or task, and as we discussed earlier, that many lines of code are likely to have errors anyway.
代码行数尽量简短。多年来,我们听说过不同公司的风格指南对于函数长度有着不同的规定。我们听到单个Python函数的最大行数限制,从 12 到 20 行不等。在这些规则中,行数被用作代码复杂度的一个参考指标,而这作为一项经验法则来看确实不赖。作为程序员,我们俩在编写代码时也会遵循类似的准则,以确保复杂度不会失控。在使用 Copilot时,我们同样可以参考这一准则。如果你要求 Copilot 生成一个函数,而它给你返回了 50 行代码,这可能意味函数命名或任务描述并不合理;而且,正如我们之前所讨论的,这么多行代码很可能会包含错误。
General value over specific use—A function that returns the number of values in a list that are greater than 1 might be a specific need for a part of your program, but there’s a way to make this better. The function should be rewritten to return the number of values in the list that are greater than another parameter. The new function would work for your use case (give the function 1 for the second parameter) and for any value other than 1. We strive to have functions be as simple but as powerful as possible.
追求通用性而非定制化。设计一个函数,如果它仅能返回列表中大于 1 的元素数量,这可能只是满足了某个程序的某个具体需求。然而,我们可以让它变得更好:重构该函数,使其能够返回列表中大于某个给定参数的元素数量。这样的新函数不仅能够适应你的原有场景(只需给第二个参数传入 1),还能适应 1 以外的其他数值。我们的目标是让函数在保持简洁的同时,发挥最大的功效。
Clear input and output—You generally don’t want a lot of parameters. That doesn’t mean you can’t have a lot of input, though. A single parameter could be a list of items (we’ll talk more about lists soon). It does mean that you want to find ways to keep the number of inputs to a minimum. You can only return one thing, but again, you can return a list so you aren’t as limited as it may appear. But if you find yourself writing a function that sometimes returns a list, sometimes returns a single value, and sometimes returns nothing, that’s probably not a good function.
清晰的输入与输出。通常情况下,你并不希望函数有太多的参数。这并不是说你不能接受大量的输入数据。例如,一个参数可以是一个由多个成员组成的列表(我们稍后会详细谈到列表)。这样做的目的是为了尽量减少输入的数量。虽然函数只能返回一个结果,但由于可以返回列表,所以你实际上并不像看起来那样受限。但如果发现自己编写的函数有时返回列表,有时又返回单个值,有时则不返回任何东西,那么这个函数很可能设计得不够合理。
3.4.2 Examples of good (and bad) leaf functions
3.4.2 一些正面例子(和反面例子)
Here are examples of good leaf functions:
以下是关于叶子函数的一些正面例子:
Compute the volume of a sphere—Given the sphere’s radius, return its volume.
“计算球体体积” —- 提供球的半径,便能得出其体积。
Find the largest number in a list—Given a list, return the largest value.
“找出列表中的最大数” —— 给定一个列表,返回其中的最大值。
Check whether a list contains a specific value—Given a list and a value, return True if the list contains the value and False if it does not.
“检查列表中是否存在某个值” —— 提供一个列表和一个特定的值,若列表中包含该值,则函数返回
true
;若不包含,则返回false
。Print the state of the checkers game—Given a 2D list representing the game board, output the game board to the screen in text.
“打印跳棋游戏的状态” —— 给定一个二维列表代表游戏棋盘,在屏幕上以文本形式输出棋盘状态。
Insert a value in a list—Given a list, a new value, and a location in the list, return a new list that is the old list with the new value inserted at the desired location.
“在列表中插入一个值” —— 给定一个列表、一个新值以及列表中的位置,返回一个新的列表,新列表的内容相当于旧列表在指定位置插入新值后的样子。
Here are examples of bad leaf functions and our reasons for why they are bad:
以下是一些反面例子,我们也解释了它们不好的原因:
Request a user’s tax information and return the amount they owe this year—Perhaps in some countries this wouldn’t be too bad, but we can’t imagine this as a single function in either the United States or Canada given the complexity of the tax rules!
“请求用户的税务信息并返回他们今年应缴的税款” —— 或许在某些国家,这个场景尚可接受;但如果是在美国或加拿大,考虑到税收制度的复杂性,我们很难将其设想为一个单独的函数。
Identify the largest value in the list and remove that value from the list—This might not seem so bad, but it’s really doing two things. The first is to find the largest value in the list. The second is to remove a value from the list. We’d recommend two leaf functions, one that finds the largest and one that removes the value from the list. However, this might make a good nonleaf function if your program needs to perform this task frequently.
“识别列表中的最大值并将其从列表中删除” —— 这种做法乍一看似乎没什么不妥,但其实它同时完成了两个任务。首先是寻找列表中的最大数值,其次是将该数值从列表中剔除。我们推荐将其拆分为两个简单的叶子函数,一个负责查找最大值,另一个负责删除指定值。当然,如果你的程序需要频繁进行这一操作,那么再准备一个非叶子函数也是一个不错的选择。
(Thinking of our dataset from chapter 2) Return the names of the quarterbacks with more than 4,000 yards of passing in the dataset—This has too much specificity. Without a doubt, the number 4,000 should be a parameter. But it’d likely be better to make a function that takes as input the position (quarterback, running back), the statistic (passing yards, games played), and the cutoff that we care about (4,000, 8,000) as parameters. This new function provides far more capability than the original, allowing a user to call the function to determine not only the names of particular quarterbacks who threw for more than 4,000 yards but also, for example, running backs who had more than 12 rushing touchdowns.
(请回想第二章提到的数据集)“列出传球码数超过 4000 码的四分卫姓名” —— 此函数过于定制化。数字 4000 无疑应该设置为一个参数。不过,更优的做法是构建一个函数,它将接收诸如位置(四分卫、跑卫)、统计数据(传球码数、比赛次数)以及我们所关注的阈值(4000、8000)等参数。这样的新函数将大大扩展其应用范围,用户不仅可以利用它来查询那些传球码数超过 4000 码的四分卫,还能找出超过12次冲球达阵的跑卫。
Determine the best movie of all time—This function is too vague. Best movie by what definition? What movies should be considered? A better version of this might be a function that determines the highest-rated movie by users given at least a minimum number of ratings. This function would likely be part of a larger program where the function would have data from a movie database (say, IMDB) and minimum number of user ratings as inputs. The output of the function would be the highest-rated movie that has at least as many ratings as specified.
“选出史上最佳影片” -- 这个任务描述过于宽泛。最佳影片是根据什么标准来评定的呢?需要考虑哪些电影作品?一个更佳的方案是设计一个函数,它能够在满足最低评分人数的前提下,找出平均评分最高的电影。这个函数可能是某个更庞大程序的组成部分,其输入数据来自电影资料库(例如 IMDB)以及评分人数的最小阈值。输出结果则是达到规定评分人数且评分最高的那一部。
Play Call of Duty—This might be the main function in the large code base for the game Call of Duty, but it is definitely not a leaf function.
“玩《使命召唤》(Call of Duty)” -- 这可能是《使命召唤》游戏的大型代码库中的
main
函数,但它肯定不是一个叶子函数。The text was updated successfully, but these errors were encountered: