第3章 函式
“函式”就像一個程式內的小程式
3.1 def語句和引數
如果呼叫print()或者len()函式,你會傳入一些值,放在括號之間,在這裡稱為“引數”。也可以自己定義接收引數的函式。
>>> def hello (name):
print('hello '+ name)
>>> hello('alice')
hello alice
>>> hello('bob')
hello bob
在這個程式的hello()函式定義中,有一個名為name的變元。“變元”是一個變數,當函式被呼叫時,引數就存放在其中。
【注】儲存在變元中的值,在函式返回後就丟失了。
3.2 返回值和return語句
函式呼叫求值的結果,稱為函式的“返回值”。
用def語句穿建立函式時,可以用return語句指定應該返回什麼值。return語句也包含以下部分
- return 關鍵字
- 函式應該返回的值或表示式
如果在return語句中使用了表示式,返回值就是該表示式求值的結果。
3.3 None值
在python中有一個值稱為None,他表示沒有值。None是NoneType資料型別的唯一值。
print()函式在螢幕上顯示文字,但他不需要返回任何值,這就和len()和input()不同。但既然所有函式呼叫都需要求值為一個返回值,那麼print()就返回None
>>> spam = print('hello')
hello
>>> None ==spam
True
>>>
在幕後,對於沒有return語句的函式定義,python都會在末尾加上return None。這類似於while或者fo迴圈隱式的以continue語句結尾。而且,如果使用帶值的return語句(也就是隻有return關鍵字本身),那麼就返回None。
3.4 關鍵字引數和print()
大多數引數是由他們在函式呼叫中的位置來識別的。但是“關鍵字引數”是有函式呼叫是加在他們前面的關鍵字來識別的。關鍵字引數通常用於可選變元。例如,print()函式有可選的變元end和sep,分別指定在引數末尾列印什麼,以及在引數之間列印什麼來隔開它們
>>> print('dog','cat','mice')
dog cat mice
>>> print('dog','cat','mice',sep=',')
dog,cat,mice
>>>
3.5 區域性作用域
在被呼叫函式內賦值的變元和變數,處於該函式的“區域性作用域”,在所有函式之外複製的變數,屬於“全域性作用域”。處於區域性作用域的變數,被稱為“區域性變數”。處於全域性作用域的變數,被稱為“全域性變數”。一個變數必是其中的一種,不能既是全域性有事區域性的。
可以將“作用域”看成是變數的容器。當作用域被銷燬時,所有儲存在該作用域內的變數值就被丟棄了。
作用域很重要,理由如下:
- 全域性作用域中的程式碼不能使用任何區域性變數
- 但是,區域性作用域可以訪問全域性變數
- 一個函式的區域性作用域中的程式碼,不能使用其他區域性作用域中的變數
- 如果在不同的作用域中,你可以用相同的名字命名不同的變數
3.5.1 區域性變數不能在全域性作用域內使用
def spam():
eggs = 111
spam()
print(eggs)
如果執行這個程式就會出錯,eggs變數只屬於spam()呼叫所建立的區域性作用域。
3.5.2 區域性作用域不能使用其他區域性作用內的變數
def spam():
eggs = 99
bacon()
print(eggs)
def bacon()
ham = 101
eggs = 0
spam()
程式執行時,spam()被呼叫,建立一個區域性作用域。區域性變數eggs被賦值為99。然後bacon()函式被呼叫,建立第二個作用域。多個區域性作用域能同時存在。在這新的區域性作用域中,區域性變數ham也被建立被賦值為101。區域性變數eggs也被建立並賦值為0。
當bacon()返回時,這次呼叫的區域性作用域被銷燬。程式執行在spam()函式中繼續,打印出eggs的值。這次spam()呼叫的區域性作用域任然存在,eggs被賦值為99.
3.5.3 全域性變數可以在區域性作用域中讀取
def spam():
print(eggs)
eggs = 42
spam()
print(eggs)
3.6 global 語句
如果需要在一個函式內修改全域性變數,就是用global語句
有四條法則,來區分一個變數是處於區域性作用域還是全域性作用域
- 如果變數在全域性作用域中使用(即在所有函式之外),它就是全域性變數
- 如果在一個函式中,有針對該變數的global語句,它就是全域性變數
- 否則,如果該變數用於函式中的賦值語句,它就是區域性變數
- 但是,如果該變數沒有用在賦值語句中,它就是全域性變數
3.7 異常處理
當程式執行出錯時,可以用try和except語句來處理。那些可能出錯的語句被放在try子句中。如果錯誤發生,程式執行就轉到接下來的except子句開始處。
如果try子句中的程式碼導致一個錯誤,程式執行就立即轉到except子句中的程式碼,一旦執行跳到except子句的程式碼中,就不會回到try的子句中了
3.8 一個小程式:猜數字
import random
secretNumber = random.randint(1,20)
print('i am think of number between 1 and 20:')
for guessesTaken in range(1,7):
print('take a guess')
guess = int(input())
if guess < secretNumber:
print('you guess is too low.')
elif guess > secretNumber:
print('you guess is too high')
else:
break
if guess == secretNumber:
print('good job!the number i was thinking of was ' + str(secretNumber)+
' and you guessed my number in ' + str(guessesTaken) + ' guesses')
else:
print('Nope. the number i was thinking of was ' + str(secretNumber))
3.11 實踐
Collatz 序列
編寫一個名為 collatz()的函式,它有一個名為 number的引數。如果引數是偶數,那麼 collatz()就打印出 number // 2,並返回該值。如果 number是奇數,collatz()就列印並返回 3 * number + 1。
然後編寫一個程式,讓使用者輸入一個整數,並不斷對這個數呼叫collatz(),直到函式返回值1(令人驚奇的是,這個序列對於任何整數都有效,利用這個序列,
你遲早會得到 1!既使數學家也不能確定為什麼。你的程式在研究所謂的“Collatz
序列”,它有時候被稱為“最簡單的、不可能的數學問題”)。
在前面的專案中新增 try 和 except 語句,檢測使用者是否輸入了一個非整數的字串。正常情況下,int()函式在傳入一個非整數字符串時,會產生 ValueError 錯誤,比如 int(‘puppy’)。在 except子句中,向用戶輸出一條資訊,告訴他們必須輸入一個整數。
示例程式碼1:
def collatz(number):
if number == 1:
return 1
elif number % 2 == 0:
numbers = number//2
print(numbers)
collatz(numbers)
elif number % 2 == 1:
numbers = 3*number+1
print(numbers)
collatz(numbers)
print('please input a number')
try:
number = int(input())
collatz(number)
except ValueError:
print('please input a integer number')
示例程式碼 2:
def collatz(number):
if number % 2 == 0:
numbers = number//2
return numbers
else:
numbers = 3*number+1
return numbers
print('please input a integer number')
try:
number=int(input())
while collatz(number) != 1:
print(collatz(number))
new_number=collatz(number)
number = new_number
collatz(number)
print(collatz(number))
except ValueError:
print('please input a integer')
【注】這兩個都是我自己寫的 感覺第一個會比較好一點