(一)返回值
調用一個有返回值的函數會生成一個返回值;通常將這個返回值賦值給變量或者作爲表達式的一部分;
def area(radius):
a = math.pi * radius**2
return a
return
語句意味着:立即從該函數返回,並且使用接下來的表達式作爲返回值;返回值可以是任意複雜的;- 在一個有返回值的函數中,最好保證程序執行的每一個流程都最終碰到一個return;【充分考慮好每一種分支情況】
(二)增量式開發(incremental development)
- 隨着函數越來越複雜,調試的時間會越來越多;爲了應對負載的程序,可以嘗試增量式開發;
- 增量式開發的目標,是通過每次只增加和測試少量代碼,來避免長時間的調試;
- 比如,在寫一個函數的時候,可以先寫一下這個函數的函數頭和形參,函數體可以用
pass
或者其他的return
語句進行代替;當這個函數頭可以運行的時候,再往函數體中增加代碼; - 當然上面的只是一個簡單的類比,只是一種簡單的思路:當想要實現一個功能的時候,尤其是複雜的功能,不要想着一步到位,可以將這個功能進行分解,或者先實現一個框架,之後再逐步完善細節;
- 增量式開發的關鍵:
- 從一個能運行的程序開始,並且每次只增加少量改動。無論你何時遇到錯誤,都能夠清楚定位錯誤的源頭;
- 使用臨時變量存儲中間值,這樣能顯示並檢查它們;
- 一旦程序能夠正確運行,就要刪除一些腳手架(scaffolfing)代碼;或者將多條語句組合成爲複合表達式,當然,前提是不影響程序的可讀性;
(三)組合
- 我們可以從一個函數的內部調用另一個函數;
- 一些臨時變量對於開發很有用,但是一旦程序正確運行了,我們可以通過合併函數調用,使得程序更加簡潔;
(四)布爾函數
- 這種類型的函數可以返回布爾類型(booleans),通常對於隱藏函數內部的複雜測試代碼非常有用;
- 布爾函數通常用於條件語句中;
def is_divisible(x, y):
if x%y == 0:
return true;
else:
return false;
==
的返回值是Boolean類型,可以直接使用這個來簡化上面的代碼:
def is_divisible(x, y):
return x % y == 0
(五)再談遞歸
到目前爲止,雖然學到的知識Python中很小的一個子集,但是實際上,這已經是一個完備的編程語言,這意味着任何能夠被計算的東西都可以用這個語言表達;
- 使用遞歸計算階乘:
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n-1)
- 程序的執行過程:【假如n == 3】
- 堆棧圖:
(六)信任之躍【一種閱讀代碼的方法】
- 跟隨程序的執行流程讀代碼,是一種方法,但是可能很快就會變得錯綜複雜;
- 另一種方法:當遇到一個函數的時候,不去跟蹤函數的執行流程,而是假設這個函數正確運行並且返回了正確的結果;
- 事實上,使用內建函數的時候已經使用的了這種方法,我們總是假設,這個內建函數的執行是正確的;
- 使用遞歸函數也是一樣的,我們不再順着執行流程,而是假設每次遞歸都能正確執行;
(七)斐波那契數列【遞歸】
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fibonacii(n-1)+fibonacci(n-2)
(八)檢查數據類型
- 上面的函數中,當輸入的參數是一個非整數的時候,這時候,遞歸將無限進行下去,因爲沒有邊界;
- 我們需要檢查傳入的參數是不是我們所希望的類型;
- 我們使用內建函數
isinstance
來驗證實參的類型:
def factorial(n):
if not isinstance(n, int):
print('Factorial is only defined for integers.')
return None
elif n<0:
print('Factorial is not defined for negative integers.')
return None
elif n == 0:
return 1
else:
return factorial(n-1)*n
- 上面的方法有時候稱之爲“監護人(Guardian)模式;通過設置監護人,保證後面的代碼不會出現錯誤;
- 當然還有更加靈活的方式:拋出異常
(九)調試
將一個大程序分解爲若干較小的函數,爲程序的調試生成的自然的檢查點;當一個程序不能如預期運行的時候,需要考慮的情況:
- 該函數獲取的實參有問題,違反先決條件;
- 該函數有些問題,違反後置條件;
- 返回值或者使用方法有問題;
實參問題
爲排除這種可能性,可以在函數的開始增加一條
函數問題
如果函數的形參沒有問題,則在函數的
return
之前,打印結果、返回值;考慮用一些簡單的值調用這個函數;
調用問題
要確保返回值被正確地使用;