首先,本文不是總結歸納,只是記錄一些有趣的知識點罷了
此外,觀前提示,請最好在嘗試獨立完成該任務後再看本文,否則就很可能失去了體驗本專案精華的機會
函式引數前的*
在專案原檔案中的dice.py 裡的 make_test_dice函式採用這樣的方式傳參
def make_test_dice(*outcomes):
# 省略內容
pass
我記得python中沒像c那樣的指標,於是查詢資料,小結如下
函式引數前一顆*會識別為元組,兩顆則識別為字典
比如我要是傳 make_test_dice(1, 2, 4, 3),outcomes就是元組(1, 2, 4, 3)
舉一個稍微複合一點點的例子
def foo(a, b=10, *args, **kwargs):
print (a)
print (b)
print (args)
print (kwargs)
foo(1, 2, 3, 4, e=5, f=6, g=7)
上述例子來自菜鳥教程,執行結果為
1
2
(3, 4)
{'e': 5, 'f': 6, 'g':7}
可發現除了定好的a、b,c和d都納入元組中,而efg有=賦值,作為字典看待
上面的例子都發生在定義函式引數列表,如果在呼叫時有*說明什麼呢?
再看一個例子
def func(num1, num2):
print(num1, num2)
num = [1, 2]
func(*num)
執行結果為
1 2
一個引數變兩,*在這裡起到了解壓引數列表的作用
但筆者尚未想到該功能應用的方便之處
Higher Order Function 高階函式
這是一個讓陸爻齊覺得十分精妙的功能,以函式為引數並返回函式,從 C 初學者的角度來說,太抽象了
就是在 Problem 7 的答案程式碼
def announce_highest(who, last_score=0, running_high=0):
"""Return a commentary function that announces when WHO's score
increases by more than ever before in the game.
NOTE: the following game is not possible under the rules, it's just
an example for the sake of the doctest
>>> f0 = announce_highest(1) # Only announce Player 1 score gains
>>> f1 = f0(12, 0)
>>> f2 = f1(12, 9)
9 point(s)! The most yet for Player 1
>>> f3 = f2(20, 9)
>>> f4 = f3(20, 30)
21 point(s)! The most yet for Player 1
>>> f5 = f4(20, 47) # Player 1 gets 17 points; not enough for a new high
>>> f6 = f5(21, 47)
>>> f7 = f6(21, 77)
30 point(s)! The most yet for Player 1
"""
assert who == 0 or who == 1, 'The who argument should indicate a player.'
# BEGIN PROBLEM 7
"*** YOUR CODE HERE ***"
def say(new_score_0, new_score_1, last_running_high = running_high):
if who == 0:
new_score = new_score_0
new_running_high = new_score_0 - last_score
else:
new_score = new_score_1
new_running_high = new_score_1 - last_score
if new_running_high > last_running_high:
last_running_high = new_running_high
print(str(new_running_high),"point(s)! The most yet for Player " + str(who))
new_run_high = last_running_high
return announce_highest(who, new_score, new_run_high)
return say
# END PROBLEM 7
這段程式碼就是記錄玩家 1 或 2 分數變化的幅度,並在最大幅度記錄更新時 print 的函式。
傳統函式(指 C/C++ 這種)要實現這種記錄更新,必須在外部儲存,用類或者其它外部變數什麼的,因為函式一旦執行完畢,內部空間將全部釋放。
下面對該程式碼做點拆解,忽略 say 的內容、斷言、測試和註釋,可看成
def announce_highest(who, last_score=0, running_high=0):
# BEGIN PROBLEM 7
"*** YOUR CODE HERE ***"
def say(new_score_0, new_score_1, last_running_high = running_high):
pass
return say
# END PROBLEM 7
可見,呼叫 announce_highest 的本質是獲取到一個 say 函式,每次呼叫 say 函式,我們都期待它能檢測是否要更新記錄,而不斷地更新最大幅度,則要不斷地獲取並呼叫 say 函式,那讓 say 返回獲取 say 函式的函式就解決了這個問題,即下面程式碼
def announce_highest(who, last_score=0, running_high=0):
# BEGIN PROBLEM 7
"*** YOUR CODE HERE ***"
def say(new_score_0, new_score_1, last_running_high = running_high):
pass
return announce_highest(who, new_score, new_run_high)
return say
# END PROBLEM 7
再看測試程式碼就清晰多了
>>> f0 = announce_highest(1) # Only announce Player 1 score gains
這裡的 f0 實際上是 who 為 1 時的 say 函式
>>> f1 = f0(12, 0)
f1 的本質是代入 new_score_0 = 12 和 new_score_1 = 0 的 say 函式執行後,返回的新的 say 函式。你問 announce_highest 去哪了?announce_highest 也返回的 say 函式,只是沒有引數代入的 say 函式而已
其它測試語句以上述類推
後面在 geek for geek 進行了更深入的學習,發現此前在 LALC 用的迭代器就是高階函式的運用