# Chapter 3 Functions 函數
In the context of programming, a function is a named sequence of statements that performs a computation. When you define a function, you specify the name and the sequence of statements. Later, you can “call” the function by name.
> 在編程的語境下,“函數”這個詞的意思是對一系列語句的組合,這些語句共同完成一種運算。定義函數的時候,你要給這個函數指定一個名字,另外還好寫出這些進行運算的語句。定義完成后,就可以通過函數名來“調用”函數。
## 3.1 Function calls 函數調用
We have already seen one example of a function call:
> 此前我們已經見識過函數調用的一個例子了:
```Python
>>> type(42)
>>> type(42)
<class 'int'>
```
The name of the function is type. The expression in parentheses is called the argument of the function. The result, for this function, is the type of the argument.
> 這個函數的名字就是tpye,括號里面的表達式叫做函數的參數。這個函數的結果是返回參數的類型。
It is common to say that a function “takes” an argument and “returns” a result. The result is also called the return value.
Python provides functions that convert values from one type to another. The int function takes any value and converts it to an integer, if it can, or complains otherwise:
> 一般來說,函數都要“傳入”一個參數,“返回”一個結果。結果也被叫做返回值。Python提供了一些轉換數值類型的函數。比如int這個函數就可以把值轉換成整形,但不是什么都能轉的,遇到不能轉換的就會報錯了,如下所示:
```Python
>>> int('32')
>>> int('32')
32
>>> int('Hello')
>>> int('Hello')
ValueError: invalid literal for int(): Hello
```
int can convert floating-point values to integers, but it doesn’t round off; it chops off the fraction part:
> int這個函數能把浮點數轉成整形,但不是很完美,小數部分就都給砍掉了。
```Python
>>> int(3.99999)
>>> int(3.99999)
3
>>> int(-2.3)
>>> int(-2.3)
-2
```
float converts integers and strings to floating-point numbers:
> float能把整形和字符串轉變成浮點數:
```Python
>>> float(32)
>>> float(32)
32.0
>>> float('3.14159')
>>> float('3.14159')
3.14159
```
Finally, str converts its argument to a string:
> 最后來看下,str可以把參數轉變成字符串:
```Python
>>> str(32)
>>> str(32)
'32'
>>> str(3.14159)
>>> str(3.14159)
'3.14159'
```
## 3.2 Math functions
Python has a math module that provides most of the familiar mathematical functions. A module is a file that contains a collection of related functions.
> Python內置了一個數學模塊,這一模塊提供了絕大部分常用的數學函數。模塊就是一系列相關函數的集合成的文件。
Before we can use the functions in a module, we have to import it with an import statement:
> 在使用模塊中的函數之前,必須先要導入這個模塊,使用導入語句:
```Python
>>> import math
>>> import math
```
This statement creates a module object named math. If you display the module object, you get some information about it:
> 這個語句建立了一個模塊對象,名字叫做math。如果你讓這個模塊對象顯示一下,你就會得到與之相關的信息了:
```Python
>>> math
>>> math
<module 'math' (built-in)>
```
The module object contains the functions and variables defined in the module. To access one of the functions, you have to specify the name of the module and the name of the function, separated by a dot (also known as a period). This format is called dot notation.
> 模塊對象包含了一些已經定義好的函數和變量。指定模塊名和函數名,要用點(也就是英文的句號)來連接模塊名和函數名,就可以調用指定的函數了。
```Python
>>> ratio = signal_power / noise_power
>>> ratio = signal_power / noise_power
>>> decibels = 10 * math.log10(ratio)
>>> decibels = 10 * math.log10(ratio)
>>> radians = 0.7
>>> radians = 0.7
>>> height = math.sin(radians)
>>> height = math.sin(radians)
```
The first example uses math.log10 to compute a signal-to-noise ratio in decibels (assuming that signal_power and noise_power are defined). The math module also provides log, which computes logarithms base e.
第一個例子用了數學的log10的函數,來計算信噪比的分貝值(假設信號強度和噪音強度都已知了)。數學模塊同事也提供了log,用自然底數e取對數的函數。
The second example finds the sine of radians. The name of the variable is a hint that sin and the other trigonometric functions (cos, tan, etc.) take arguments in radians. To convert from degrees to radians, divide by 180 and multiply by π:
> 第二個例子是對弧度值計算正弦值。通過變量名你應該能推測出正弦以及其他的三角函數(比如余弦、正切等等)都要用弧度值作為參數。所以要把角度的值從度轉換成弧度,方法就是除以180然后再乘以圓周率π:
```Python
>>> degrees = 45
>>> degrees = 45
>>> radians = degrees / 180.0 * math.pi
>>> radians = degrees / 180.0 * math.pi
>>> math.sin(radians)
>>> math.sin(radians)
0.707106781187
```
The expression math.pi gets the variable pi from the math module. Its value is a floating-point approximation of π, accurate to about 15 digits.
> math.pi這個表達式從數學模塊中得到π的一個大概精確到15位的近似值,存成一個浮點數。
If you know trigonometry, you can check the previous result by comparing it to the square root of two divided by two:
> 了解了三角函數之后,你可以用試著把2的平方根除以二,然后對比一下這個結果和上一個結果:
```Python
>>> math.sqrt(2) / 2.0
>>> math.sqrt(2) / 2.0
0.707106781187
```
> 譯者注:畫一個三角形就知道了,45度角兩直角邊是單位1,斜邊必然是2的平方根了,對應的正弦余弦也都是這個值了。大家應該能理解吧?
## 3.3 Composition 組合
So far, we have looked at the elements of a program—variables, expressions, and statements—in isolation, without talking about how to combine them.
> 目前為止,我們已經見識了一個程序所需要的大部分元素了:變量、表達式、語句。不過咱們都是一個個單獨看到的,還沒有把它們結合起來試試。
One of the most useful features of programming languages is their ability to take small building blocks and compose them. For example, the argument of a function can be any kind of expression, including arithmetic operators:
> 一門編程語言最有用的功能莫過于能夠用一個個小模塊來拼接創作。例如函數的參數可以是任何一種表達式,包括代數運算符:
```Python
x = math.sin(degrees / 360.0 * 2 * math.pi) ?
```
And even function calls:
> 再或者函數的調用本身也可以作為參數:
```Python
x = math.exp(math.log(x+1))
```
Almost anywhere you can put a value, you can put an arbitrary expression, with one exception: the left side of an assignment statement has to be a variable name. Any other expression on the left side is a syntax error (we will see exceptions to this rule later).
> 你可以在任何地方放一個值,放任何一個表達式,只有一個例外:一個聲明語句的左邊必須是變量名。任何其他的表達式放到等號左邊都會導致語法錯誤(當然也有例外,等會再給介紹)。
```Python
>>> minutes = hours * 60 # right
>>> minutes = hours * 60 # right
>>> hours * 60 = minutes # wrong!
>>> hours * 60 = minutes # wrong!
SyntaxError: can't assign to operator
```
> 譯者注:上述例子里面把表達式復制為變量是不行的,所說的例外估計是指尤達大師命名法,這個后面看到再說。
## 3.4 Adding new functions 添加新函數
So far, we have only been using the functions that come with Python, but it is also possible to add new functions. A function definition specifies the name of a new function and the sequence of statements that run when the function is called.
Here is an example:
> 目前我們學到了一些Python自帶的函數,自己添加新的函數也是可以的。函數定義要指定這個心函數的名字,還需要一系列語句放到這個函數里面,當調用這個函數的時候,就會運行這些語句了。
```Python
def print_lyrics():
print("I'm a lumberjack, and I'm okay.")
print("I sleep all night and I work all day.")
```
def is a keyword that indicates that this is a function definition. The name of the function is print_lyrics. The rules for function names are the same as for variable names: letters, numbers and underscore are legal, but the first character can’t be a number. You can’t use a keyword as the name of a function, and you should avoid having a variable and a function with the same name.
> 這里的def就是一個關鍵詞,意思是這是在定義一個函數。函數的名字就是print_lyrics,函數的命名規則和變量命名規則基本差不多,都是字幕梳子或者下劃線,但是不能用數字打頭。另外也不能用關鍵詞做函數名,還要注意盡量避免函數名和變量名發生重復。
The empty parentheses after the name indicate that this function doesn’t take any arguments.
> 函數名后面的括號是空的,意思是這個函數不需要參數。
The first line of the function definition is called the header; the rest is called the body. The header has to end with a colon and the body has to be indented. By convention, indentation is always four spaces. The body can contain any number of statements.
> 函數定義的第一行叫做頭部,剩下的叫做函數體。函數頭部的末尾必須有一個冒號,函數體必須是相對函數頭部有縮進的,距離行首相對于函數頭要有四個空格的距離。函數體可以有任意長度的語句。
(譯者注:縮進是Python最強制的要求,本書的翻譯用的MarkDown在生成的時候可能未必能夠完美縮進,所以大家多注意一下自己調整哈,這個超級重要!)
The strings in the print statements are enclosed in double quotes. Single quotes and double quotes do the same thing; most people use single quotes except in cases like this where a single quote (which is also an apostrophe) appears in the string.
> 在打印語句中,要打印的字符串需要用雙引號括著。單引號和雙引號效果一樣,除非是字符串中已經出現了單引號,大家一般都是用單引號的。
All quotation marks (single and double) must be “straight quotes”, usually located next to Enter on the keyboard. “Curly quotes”, like the ones in this sentence, are not legal in Python.
> 所有的引號都必須是鍵盤上直接是引號的那個"鍵,無論是單引號還是雙引號。就是回車鍵左邊那個。“Curly quotes”這種引號,在Python里面是非法的。
If you type a function definition in interactive mode, the interpreter prints dots (...) to let you know that the definition isn’t complete:
> 如果你在交互模式下面定義函數,解釋器會顯示三個小點來提醒你定義還沒有完成:
```Python
>>> def print_lyrics():
>>> def print_lyrics():
...
print("I'm a lumberjack, and I'm okay.") ...
print("I sleep all night and I work all day.") ...
```
To end the function, you have to enter an empty line.
Defining a function creates a function object, which has type function:
> 在函數定義完畢的結尾,必須輸入一行空白行。定義函數會創建一個函數類的對象,有type函數。
```Python
>>> print(print_lyrics)
>>> print(print_lyrics)
<function print_lyrics at 0xb7e99e9c>
>>> type(print_lyrics)
>>> type(print_lyrics)
<class 'function'>
```
The syntax for calling the new function is the same as for built-in functions:
> 調用新函數的語法和調用內置函數是一樣的:
```Python
>>> print_lyrics()
>>> print_lyrics()
I'm a lumberjack, and I'm okay. I sleep all night and I work all day.
```
Once you have defined a function, you can use it inside another function. For example, to repeat the previous refrain, we could write a function called repeat_lyrics:
> 一旦你定義了一個函數,就可以在其它函數里面來調用這個函數。比如咱們重復一下剛剛討論的,寫一個叫做重repeat_lyrics的函數。
```Python
def repeat_lyrics():
print_lyrics()
print_lyrics()
```
And then call repeat_lyrics:
> 然后調用一下這個函數:
```Python
>>> repeat_lyrics()
>>> repeat_lyrics()
I'm a lumberjack, and I'm okay. I sleep all night and I work all day. I'm a lumberjack, and I'm okay. I sleep all night and I work all day.
```
But that’s not really how the song goes.
> 當然了,實際這首歌可不是這樣的哈。
## 3.5 Definitions and uses 定義并使用
Pulling together the code fragments from the previous section, the whole program looks like this:
> 把前面這些小塊的代碼來整合一下,整體上程序看著大概是這樣的:
```Python
def print_lyrics():
print("I'm a lumberjack, and I'm okay.")
print("I sleep all night and I work all day.")
def repeat_lyrics():
print_lyrics()
print_lyrics()
repeat_lyrics()
```
This program contains two function definitions: print_lyrics and repeat_lyrics. Function definitions get executed just like other statements, but the effect is to create function objects. The statements inside the function do not run until the function is called, and the function definition generates no output.
> 這個程序包含兩個函數的定義:print_lyrics以及repeat_lyrics,函數定義的執行就和其他語句一樣,但是效果是創建函數對象。函數定義中的語句直到函數被調用的時候才會運行,函數的定義本身不會有任何輸出。
As you might expect, you have to create a function before you can run it. In other words, the function definition has to run before the function gets called.
> 如你所愿了,你可以建立一個函數,然后運行一下試試了。換種說法就是,在調用之前一定要先把函數定義好。
As an exercise, move the last line of this program to the top, so the function call appears before the definitions. Run the program and see what error message you get.
Now move the function call back to the bottom and move the definition of print_lyrics after the definition of repeat_lyrics. What happens when you run this program?
> 作為練習,把這個程序的最后一行放到頂部,這樣函數調用就在函數定義之前了。運行一下看看出錯的信息是什么。
> 然后再把函數調用放到底部,把print_lyrics這個函數的定義放到repeat_lyrics這個函數的后面。再看看這次運行會出現什么樣子?
## 3.6 Flow of execution 運行流程
To ensure that a function is defined before its first use, you have to know the order statements run in, which is called the flow of execution.
> 為了確保一個函數在首次被調用之前已經定義,你必須要之道語句運行的順序,也就是所謂『運行流程』。
Execution always begins at the first statement of the program. Statements are run one at a time, in order from top to bottom.
> 一個Python程序都是從第一個語句開始運行的。從首至尾,每次運行一個語句。
Function definitions do not alter the flow of execution of the program, but remember that statements inside the function don’t run until the function is called.
> 函數的定義并不會改變程序的運行流程,但要注意,函數體內部的語句只有在函數被調用的時候才會運行。
A function call is like a detour in the flow of execution. Instead of going to the next statement, the flow jumps to the body of the function, runs the statements there, and then comes back to pick up where it left off.
> 函數調用就像是運行流程有了繞道的行為。沒有直接去執行下一個語句,運行流跳入到函數體內,運行里面的語句,然后再回來從離開的地方繼續執行。
That sounds simple enough, until you remember that one function can call another. While in the middle of one function, the program might have to run the statements in another function. Then, while running that new function, the program might have to run yet another function!
> 這么解釋很簡明易懂了,只要你記住一個函數可以調用另一個就行。在一個函數的中間,程序有可能必須運行一下其他函數中的語句。所以運行新的函數的時候,程序可能也必須運行其他的函數!
譯者注:看著很繞嘴,其實蠻簡單的,就是跳出跳入互相調用而已。
Fortunately, Python is good at keeping track of where it is, so each time a function completes, the program picks up where it left off in the function that called it. When it gets to the end of the program, it terminates.
> 幸運的是,Python很善于追蹤應該執行的位置,所以每次一個函數執行完畢了,程序都會回到當時跳出的位置,然后繼續運行。等執行到了程序的末尾,就終止了。
In summary, when you read a program, you don’t always want to read from top to bottom. Sometimes it makes more sense if you follow the flow of execution.
> 總的來說,你閱讀一個程序的時候,并不一定總是要從頭到尾來讀的。有時候你要按照運行流程來讀才更好理解。
## 3.7 Parameters and arguments 形式參數和實際參數
譯者注:這里提到的形參和實參實際上是傳值方式的區別,這個在最基本的編程入門課程中老師應該都比較強調的。實際參數就是調用函數時候傳給他的那個參數;而形式參數可以理解為函數內部定義用的參數。老外對這個的思辯也很多。這里我先不說太多,翻譯著再看。
大家可以去網上多搜索一下,比如在[StackOverflow](http://stackoverflow.com/questions/1788923/parameter-vs-argument)和[MSDN](https://msdn.microsoft.com/en-us/library/9kewt1b3.aspx)
Some of the functions we have seen require arguments. For example, when you call math.sin you pass a number as an argument. Some functions take more than one argument: math.pow takes two, the base and the exponent.
> 我們已經看到了一些函數了,他們都需要實際參數。比如當你調用數學的正弦函數的時候你就需要給它一個數值作為實際參數。有的函數需要一個以上的實際參數,比如冪指數函數需要兩個,一個是底數,一個是冪次。
Inside the function, the arguments are assigned to variables called parameters. Here is a definition for a function that takes an argument:
> 在函數里面,實際參數會被賦值給形式參數。下面就是一個使用單個實際參數的函數的定義:
```Python
def print_twice(bruce):
print(bruce)
print(bruce)
```
This function assigns the argument to a parameter named bruce. When the function is called, it prints the value of the parameter (whatever it is) twice.
This function works with any value that can be printed.
> 這個函數把傳來的實際參數的值賦給了一個名字叫做burce的形式參數。當函數被調用的時候,就會打印出形式參數的值兩次(無論是什么內容)。任何能打印的值都適用于這個函數。
```Python
>>> print_twice('Spam')
>>> print_twice('Spam')
Spam
Spam
>>> print_twice(42)
>>> print_twice(42)
42
42
>>> print_twice(math.pi)
>>> print_twice(math.pi)
3.14159265359
3.14159265359
```
The same rules of composition that apply to built-in functions also apply to programmer-defined functions, so we can use any kind of expression as an argument for print_twice:
適用于Python內置函數的組合規則對自定義的函數也是適用的,所以我們可以把表達式作為實際參數:
```Python
>>> print_twice('Spam '*4)
>>> print_twice('Spam '*4)
Spam Spam Spam Spam
Spam Spam Spam Spam
>>> print_twice(math.cos(math.pi))
>>> print_twice(math.cos(math.pi))
-1.0
-1.0
```
The argument is evaluated before the function is called, so in the examples the expressions 'Spam '*4 and math.cos(math.pi) are only evaluated once.
You can also use a variable as an argument:
> 實際參數在函數被調用之前要先被運算一下,所以上面例子中作為實際參數的兩個表達式都是在print_twice函數調用之前僅計算了一次。
> 當然了,也可以用變量做實際參數了:
```Python
>>> michael = 'Eric, the half a bee.'
>>> michael = 'Eric, the half a bee.'
>>> print_twice(michael)
>>> print_twice(michael)
Eric, the half a bee. Eric, the half a bee.
```
The name of the variable we pass as an argument (michael) has nothing to do with the name of the parameter (bruce). It doesn’t matter what the value was called back home (in the caller); here in print_twice, we call everybody bruce.
> 咱們傳遞給函數的這個實際參數是一個變量,這個變量名michael和函數內部的形式參數bruce沒有任何關系。在程序主體內部參數傳過去就行了,參數名字對于函數內部沒有作用;比如在這個print_twice函數里面,任何傳來的值,在這個print_twice函數體內,都被叫做bruce。
譯者注:這里要跟大家解釋一下,傳遞參數的時候用的是實際參數,是把這個實際參數的值交給調用的函數,函數內部接收這個值,可以命名成任意其他名字的形式參數,差不多就這么個意思了。
## 3.8 Variables and parameters are local 函數內部變量和形參都是局部的
When you create a variable inside a function, it is local, which means that it only exists inside the function. For example:
> 在函數內部建立一個變量,這個變量是僅在函數體內部才存在。例如:
```Python
def cat_twice(part1, part2):
cat = part1 + part2
print_twice(cat)
```
This function takes two arguments, concatenates them, and prints the result twice. Here is an example that uses it:
> 這個函數得到兩個實參,把它們連接起來,然后調用print_twice函數來輸出結果兩次。
```Python
>>> line1 = 'Bing tiddle '
>>> line1 = 'Bing tiddle '
>>> line2 = 'tiddle bang.'
>>> line2 = 'tiddle bang.'
>>> cat_twice(line1, line2)
>>> cat_twice(line1, line2)
Bing tiddle tiddle bang.
Bing tiddle tiddle bang.
```
When cat_twice terminates, the variable cat is destroyed. If we try to print it, we get an exception:
> 當cat_twice運行完畢了,這個名字叫做cat的變量就銷毀了。咱們再嘗試著打印它一下,就會得到異常:
```Python
>>> print(cat)
>>> print(cat)
NameError: name 'cat' is not defined
```
Parameters are also local. For example, outside print_twice, there is no such thing as bruce.
> 形式參數也是局部起作用的。例如在print_twice這個函數之外,是不存在bruce這個變量的。
譯者注:當然你可以在函數外定義一個同名變量叫做bruce,但這兩個沒有關系,大家可以動手自己試試,這也是作者所鼓勵的一種探索思維。
## 3.9 Stack diagrams 棧圖
To keep track of which variables can be used where, it is sometimes useful to draw a stack diagram. Like state diagrams, stack diagrams show the value of each variable, but they also show the function each variable belongs to.
> 要追蹤一個變量能在哪些位置使用,咱們就可以畫個圖表來實現,這種圖表叫做棧圖。棧圖和我們之前提到的狀態圖有些相似,也會表征每個變量的值,不同的是棧圖還會標識出每個變量所屬的函數。
Each function is represented by a frame. A frame is a box with the name of a function beside it and the parameters and variables of the function inside it. The stack diagram for the previous example is shown in Figure 3.1.
> 每個函數都用一個框架來表示。框架的邊上要標明函數的名字,框內填寫函數內部的形參和變量。上文中樣例代碼的棧圖如下圖3.1所示。

Figure 3.1: Stack diagram.
> 圖3.1 棧圖
The frames are arranged in a stack that indicates which function called which, and so on. In this example, print_twice was called by cat_twice, and cat_twice was called by \_\_main\_\_, which is a special name for the topmost frame. When you create a variable outside of any function, it belongs to\_\_main\_\_.
> 一個棧中的這些框也表示了函數調用的關系等等。在上面這個例子中,print_twice被cat_twice調用了兩次,而cat_twice被\_\_main\_\_這個函數調用。\_\_main\_\_這個函數很特殊,屬于最外層框架,也被叫做主函數。當你在所有函數之外建立一個變量的時候,這個變量就屬于主函數所有。
Each parameter refers to the same value as its corresponding argument. So,part1 has the same value as line1, part2 has the same value as line2, and bruce has the same value as cat.
> 每個形式參數都保存了所對應的實際參數的值。因此part1的值和line1一樣,part2的值就和line2一樣,同理可知bruce的值就和cat一樣了。
If an error occurs during a function call, Python prints the name of the function, the name of the function that called it, and the name of the function that called that, all the way back to \_\_main\_\_.
> 如果函數調用的時候出錯了,Python會打印出這個出錯函數的名字,調用這個出錯函數的函數名,以及調用這個調用了出錯函數的函數的函數名,一直追溯到主函數。(譯者注:好繞口哈。。。就是會溯源回去啦。)
For example, if you try to access cat from within print_twice, you get a NameError:
> 例如,如果你想在print_twice這個函數中讀取cat的值,就會得到一個變量名錯誤:
```Python
Traceback (innermost last):
File "test.py", line 13, in __main__
cat_twice(line1, line2)
File "test.py", line 5, in cat_twice
print_twice(cat)
File "test.py", line 9, in print_twice
print(cat)
NameError: name 'cat' is not defined
```
This list of functions is called a traceback. It tells you what program file the error occurred in, and what line, and what functions were executing at the time. It also shows the line of code that caused the error.
> 這個一系列的函數列表,就是一個追溯了。這回告訴你哪個程序文件出了錯誤,哪一行出了錯誤,以及當時哪些函數在運行。還會告訴你引起錯誤的代碼所在行號。(譯者注:這個簡直太棒了,大家一定要留心這個功能以及出錯提示,以后要用來解決很多bug呢。)
The order of the functions in the traceback is the same as the order of the frames in the stack diagram. The function that is currently running is at the bottom.
> 追溯中對函數順序的排列是同棧圖的方框順序一樣的。當前運行的函數會放在最底部。
## 3.10 Fruitful functions and void functions 有返回值的函數 和 無返回值的函數
Some of the functions we have used, such as the math functions, return results; for lack of a better name, I call them fruitful functions. Other functions, like print_twice, perform an action but don’t return a value. They are called void functions.
> 咱們用過的一些函數,比如數學的函數,都會返回各種結果;也沒別的好名字,就叫他們有返回值函數。其他的函數,比如print_twice,都是進行一些操作,但不返回值。那就叫做無返回值函數好了。
When you call a fruitful function, you almost always want to do something with the result; for example, you might assign it to a variable or use it as part of an expression:
> 當你調用一個有返回值的函數的時候,一般總是要利用一下結果的;比如,你可能需要把結果賦值給某個變量,然后在表達式里面來使用一下:
```Python
x = math.cos(radians)
golden = (math.sqrt(5) + 1) / 2
```
When you call a function in interactive mode, Python displays the result:
> 當你在交互模式調用一個函數的時候,Python會顯示結果:
```Python
>>> math.sqrt(5) 2.2360679774997898
>>> math.sqrt(5) 2.2360679774997898
```
But in a script, if you call a fruitful function all by itself, the return value is lost forever!
> 如果是腳本模式,你運行一個有返回值的函數,但沒有利用這個返回值,這個返回值就會永遠丟失了!(譯者注:只要有返回值就一定要利用!)
```Python
math.sqrt(5)
```
This script computes the square root of 5, but since it doesn’t store or display the result, it is not very useful.
> 這個腳本計算了5的平方根,但沒存儲下來,也沒有顯示出來,所以就根本沒用了。
Void functions might display something on the screen or have some other effect, but they don’t have a return value. If you assign the result to a variable, you get a special value called None.
> 無返回值的函數要么就是屏幕上顯示出一些內容,要么就有其他的功能,但就是沒有返回值。如果你把這種函數的結果返回給一個變量,就會的到特殊的值:空。
```Python
>>> result = print_twice('Bing')
>>> result = print_twice('Bing')
Bing Bing
>>> print(result)
>>> print(result)
None
```
The value None is not the same as the string 'None'. It is a special value that has its own type:
> 這種None是空值的意思,和字符串'None'是不一樣的。是一種特殊的值,并且有自己的類型。(譯者注,就相當于null了。)
```Python
>>> print(type(None))
>>> print(type(None))
<class 'NoneType'>
```
The functions we have written so far are all void. We will start writing fruitful functions in a few chapters.
> 我們目前為止寫的函數還都是無返回值的。接下來的新的章節里面,咱們就要開始寫一些有返回值的函數了。
## 3.11 Why functions? 為啥要用函數?
It may not be clear why it is worth the trouble to divide a program into functions. There are several reasons:
> 為什么要費這么多力氣來把程序劃分成一個個函數呢?這么麻煩值得么?原因如下:
* Creating a new function gives you an opportunity to name a group of statements, which makes your program easier to read and debug.
> * 創建一個新的函數,你就可以把一組語句用一個名字來命名,這樣你的程序讀起來就清晰多了,后期維護調試也方便。
* Functions can make a program smaller by eliminating repetitive code. Later, if you make a change, you only have to make it in one place.
> * 函數的出現能夠避免代碼冗余,程序內的一些重復的內容就會簡化了,變得更小巧。而且在后期進行修改的時候,你只要改函數中的一處地方就可以了,很方便。
* Dividing a long program into functions allows you to debug the parts one at a time and then assemble them into a working whole.
> * 把長的程序切分成一個個函數,你就可以一步步來debug調試,每次只應對一小部分就可以,然后把它們組合起來就可以用了。
* Well-designed functions are often useful for many programs. Once you write and debug one, you can reuse it.
> * 精細設計的函數會對很多程序都有用處。一旦你寫好了并且除了錯,這種函數代碼可以再利用。
## 3.12 Debugging 調試
One of the most important skills you will acquire is debugging. Although it can be frustrating, debugging is one of the most intellectually rich, challenging, and interesting parts of programming.
> 給程序調試是你應當掌握的最關鍵技能之一了。盡管調試的過程會有挫敗感,也依然是最滿足智力,最有挑戰性,也是編程過程中最有趣的一個項目了。
In some ways debugging is like detective work. You are confronted with clues and you have to infer the processes and events that led to the results you see.
> 某種程度上,調試像是偵探工作一樣。你面對著很多線索,必須推斷出導致當前結果的整個過程和事件。
Debugging is also like an experimental science. Once you have an idea about what is going wrong, you modify your program and try again. If your hypothesis was correct, you can predict the result of the modification, and you take a step closer to a working program.
> 調試也有點像一門實驗科學。一旦你有了一個關于所出現的錯誤的想法,你就修改一下程序再試試看。如果你的假設是正確的,你就能夠預料到修改導致的結果,這樣在編程的水平上,你就上了一層臺階了,距離讓程序工作起來也更近了。
If your hypothesis was wrong, you have to come up with a new one. As Sherlock Holmes pointed out, “When you have eliminated the impossible, whatever remains, however improbable, must be the truth.” (A. Conan Doyle, The Sign of Four)
> 如果你的推測是錯誤的,你必須提出新的來。就像夏洛克.福爾摩斯之處的那樣,『當你剔除了所有那些不可能,剩下的無論多么荒謬,都必然是真相。』(引自柯南道爾的小說《福爾摩斯探案:四簽名》)
For some people, programming and debugging are the same thing. That is, programming is the process of gradually debugging a program until it does what you want. The idea is that you should start with a working program and make small modifications, debugging them as you go.
> 對于一些人來說,編程和調試是一回事。也就是說,編程就是對一個程序逐漸進行調試,一直到程序按照設想工作為止。這種思想意味著你要從一段能工作的程序來起步,一點點做小修改和調試。
For example, Linux is an operating system that contains millions of lines of code, but it started out as a simple program Linus Torvalds used to explore the Intel 80386 chip. According to Larry Greenfield, “One of Linus’s earlier projects was a program that would switch between printing AAAA and BBBB. This later evolved to Linux.” (The Linux Users’ Guide Beta Version 1).
> 例如,Linux是一個有上百萬行代碼的操作系統,但最早它起源于Linus Torvalsd的一段小代碼。這個小程序是作者用來探索Intel的80386芯片的。根據Larry Greenfield回憶,『Linus早起的項目就是很小的一個程序,這個程序能夠在輸出AAAA和BBBB之間進行轉換。這后來就發展除了Linux了。』(引用自Linux用戶參考手冊beta1版)
## 3.13 Glossary 術語列表
function:
A named sequence of statements that performs some useful operation. Functions may or may not take arguments and may or may not produce a result.
> 函數:一系列有序語句的組合,有自己的名字,并且用在某些特定用途。可以要求輸入參數,也可以沒有參數,可以返回值,也可以沒有返回值。
function definition:
A statement that creates a new function, specifying its name, parameters, and the statements it contains.
> 函數定義:創建新函數的語句,確定函數的名字,形式參數,以及函數內部的語句。
function object:
A value created by a function definition. The name of the function is a variable that refers to a function object.
> 函數對象:由函數定義所創建的值,函數名字指代了這一函數對象。
header:
The first line of a function definition.
> 函數頭:函數定義的第一行。
body:
The sequence of statements inside a function definition.
> 函數體:函數定義內部的一系列有序語句。
parameter:
A name used inside a function to refer to the value passed as an argument.
> 形式參數:用來在函數內部接收實際參數傳來的值,并被函數在函數內部使用。
function call:
A statement that runs a function. It consists of the function name followed by an argument list in parentheses.
> 函數調用:運行某個函數的語句。包括了函數的名字以及括號,括號內放函數需要的實際參數。
argument:
A value provided to a function when the function is called. This value is assigned to the corresponding parameter in the function.
> 實際參數:當函數被調用的時候,提供給函數的值。這個值會被函數接收,賦給函數內部的形式參數。
local variable:
A variable defined inside a function. A local variable can only be used inside its function.
> 局部變量:函數體內定義的變量。局部變量只在函數內部有效。
return value:
The result of a function. If a function call is used as an expression, the return value is the value of the expression.
> 返回值:函數返回的結果。如果一個函數調用被用作了表達式,這個返回值就是這個表達式所代表的值。
fruitful function:
A function that returns a value.
> 有返回值函數:返回一個值作為返回值的函數。
void function:
A function that always returns None.
> 無返回值函數:不返回值,只返回一個空None的函數。
None:
A special value returned by void functions.
> 空值:無返回值函數所返回的一種特殊的值。
module:
A file that contains a collection of related functions and other definitions.
> 模塊:包含一系列相關函數以及其他一些定義的文件。
import statement:
A statement that reads a module file and creates a module object.
> 導入語句:讀取模塊并且創建一個模塊對象的語句。
module object:
A value created by an import statement that provides access to the values defined in a module.
> 模塊對象:導入語句創建的一個值,允許訪問模塊所定義的值。
dot notation:
The syntax for calling a function in another module by specifying the module name followed by a dot (period) and the function name.
> 點符號:調用某一個模塊的某一函數的語法形式,就是模塊名后加一個點,也就是英文的句號,再加函數名。
composition:
Using an expression as part of a larger expression, or a statement as part of a larger statement.
> 組合:把表達式作為更大的表達式的一部分,或者把語句作為更大語句的一部分。
flow of execution:
The order statements run in.
> 運行流程:語句運行的先后次序。
stack diagram:
A graphical representation of a stack of functions, their variables, and the values they refer to.
> 棧圖:對函數關系、變量內容及結構的圖形化表示。
frame:
A box in a stack diagram that represents a function call. It contains the local variables and parameters of the function.
> 框架:棧圖中的方框,表示了一次函數調用。包括函數的局部變量和形式參數。
traceback:
A list of the functions that are executing, printed when an exception occurs.
> 追蹤:對運行中函數的列表,當有異常的時候就會輸出。
## 3.14 Exercises 練習
### Exercise 1 練習1
Write a function named right_justify that takes a string named s as a parameter and prints the string with enough leading spaces so that the last letter of the string is in column 70 of the display.
> 寫一個名叫right_justify的函數,形式參數是名為s的字符串,將字符串打印,前面流出足夠的空格,讓字符串最后一個字幕在第70列顯示。
```Python
>>> right_justify('monty') monty
>>> right_justify('monty') monty
```
Hint: Use string concatenation and repetition. Also, Python provides a built-in function called len that returns the length of a string, so the value of len('monty') is 5.
> 提示:使用字符拼接和重復來實現。另外Python還提供了內置的名字叫做len的函數,可以返回一個字符串的長度,比如len('monty')的值就是5了。
### Exercise 2 練習2
A function object is a value you can assign to a variable or pass as an argument. For example, do_twice is a function that takes a function object as an argument and calls it twice:
> 你可以把一個函數對象作為一個值賦給一個變量或者作為一個實際參數來傳遞給其他函數。比如,do_twice就是一個把其他函數對象當做參數的函數,它的功能是調用對象函數兩次:
```Python
def do_twice(f):
f()
f()
```
Here’s an example that uses do_twice to call a function named print_spam twice.
> 下面是另一個例子,這里用了do_twice來調用一個名叫print_spam的函數兩次。
```Python
def print_spam():
print('spam')
do_twice(print_spam)
```
1.Type this example into a script and test it.
> 把上面的例子寫成腳本然后試一下。
2.Modify do_twice so that it takes two arguments, a function object and a value, and calls the function twice, passing the value as an argument.
> 修改一下do_twice這個函數,讓它接收兩個實際參數,一個是函數對象,一個是值,調用對象函數兩次,并且賦這個值給對象函數作為實際參數。
3.Copy the definition of print_twice from earlier in this chapter to your script.
> 把print_twice這個函數的定義復制到你的腳本里面,去本章開頭找一下這個例子哈。
4.Use the modified version of do_twice to call print_twice twice, passing'spam' as an argument.
> 用修改過的這個do_twice來調用print_twice兩次,用字符串『spam』傳遞過去作為實際參數。
5.Define a new function called do_four that takes a function object and a value and calls the function four times, passing the value as a parameter. There should be only two statements in the body of this function, not four.
> 定義一個新的函數,名字叫做do_four,使用一個函數對象和一個值作為實際參數,調用這個對象函數四次,傳遞這個值作過去為對象函數的一個形式參數。這個函數體內只要有兩個語句就夠了,而不是四個。
[Solution](http://thinkpython2.com/code/do_four.py)
> [樣例代碼](http://thinkpython2.com/code/do_four.py):
### Exercise 3 練習三
Note: This exercise should be done using only the statements and other features we have learned so far.
> 注意:這個練習應該只用咱們目前學習過的語句和其他功能來實現。
1.Write a function that draws a grid like the following:
> 寫一個函數,輸出如下:

Hint: to print more than one value on a line, you can print a comma-separated sequence of values:
> 提示:要一次打印超過一行,可以用逗號分隔一下就能換行了。如下所示:
```Python
print('+', '-')
```
By default, print advances to the next line, but you can override that behavior and put a space at the end, like this:
> 默認情況下,print會打印到下一行,你可以手動覆蓋掉這個行為,在末尾輸出一個空格就可以了:
```Python
print('+', end=' ')
print('-')
```
The output of these statements is '+ -'.
> 上面的語句輸出結果就是:'+ -'。
A print statement with no argument ends the current line and goes to the next line.
> 沒有參數的print語句會把當前的行結束,去下一行。
2.Write a function that draws a similar grid with four rows and four columns.
> 寫一個四行四列的小網格繪制的程序。
[Solution](http://thinkpython2.com/code/grid.py)
[樣例](http://thinkpython2.com/code/grid.py)
Credit: This exercise is based on an exercise in Oualline, Practical C Programming, Third Edition, O’Reilly Media, 1997.
> 此練習基于Oualline的書《實踐C語言編程》第三版,O'Reilly出版社,1997年版
- 介紹
- Think Python
- Chapter 0 Preface 前言
- Chapter 1 The way of the program 編程之路
- Chapter 2 Variables, expressions and statements 變量,表達式,語句
- Chapter 3 Functions 函數
- Chapter 4 Case study: interface design 案例學習:交互設計
- Chapter 5 Conditionals and recursion 條件循環
- Chapter 6 Fruitful functions 有返回值的函數
- Chapter 7 Iteration 迭代
- Chapter 8 Strings 字符串
- Chapter 9 Case study: word play 案例學習:單詞游戲
- Chapter 10 Lists 列表
- Chapter 11 Dictionaries 字典
- Chapter 12 Tuples 元組
- Chapter 13 Case study: data structure selection 案例學習:數據結構的選擇
- Chapter 14 Files 文件
- Chapter 15 Classes and objects 類和對象
- Chapter 16 Classes and functions 類和函數
- Chapter 17 Classes and methods 類和方法
- Chapter 18 Inheritance 繼承
- Chapter 19 The Goodies 額外補充