先看一段很多人都寫過的程式。三個科目,各要算人數、平均、最高分:
math_scores = [88, 72, 95, 60, 78]
eng_scores = [70, 85, 91, 66, 80]
sci_scores = [90, 78, 84, 72, 95]
total = sum(math_scores)
print(f'數學 共 {len(math_scores)} 人,平均 {total / len(math_scores):.1f} 分,最高 {max(math_scores)} 分')
total = sum(eng_scores)
print(f'英文 共 {len(eng_scores)} 人,平均 {total / len(eng_scores):.1f} 分,最高 {max(eng_scores)} 分')
total = sum(sci_scores)
print(f'自然 共 {len(sci_scores)} 人,平均 {total / len(sci_scores):.1f} 分,最高 {max(sci_scores)} 分')數學 共 5 人,平均 78.6 分,最高 95 分
英文 共 5 人,平均 78.4 分,最高 91 分
自然 共 5 人,平均 83.8 分,最高 95 分程式能跑,結果也對。問題在於同一件事寫了三次——如果老師說平均要改成取到小數第二位,你得改三個地方;漏改一個,畫面上就會有一行格式不一樣,而且不會有任何錯誤訊息提醒你。再加兩科就是五份,改一次要動五個地方。
函式(function)就是為了這件事存在的:把一段會重複用到的程式碼取個名字,之後用名字呼叫它。
第一個函式:def 把程式碼包起來
語法只有兩個要素——def 加上名字,然後縮排寫進要執行的內容:
def say_hello():
print('哈囉,歡迎使用成績系統')
say_hello()
say_hello()哈囉,歡迎使用成績系統
哈囉,歡迎使用成績系統有三件事要留意。
`def` 那一行只是「定義」,不會執行。Python 讀到 def say_hello(): 時只是把這段程式碼記起來、掛上 say_hello 這個名字,裡面的 print 一次都不會跑。真正執行是在你寫 say_hello() 的時候——名字後面那對小括號才是「呼叫」。少了括號變成 say_hello,Python 會以為你只是在提到這個函式本身,什麼都不會發生。
縮排決定範圍。def 下面縮排的每一行都屬於這個函式,回到不縮排就是離開函式了。這跟 if、for 的規則一樣。
函式要先定義才能呼叫。Python 由上往下執行,把呼叫寫在 def 前面會得到 NameError。
參數與回傳值:函式的輸入與輸出
上面那個函式每次都印一樣的字,用處不大。要讓它有變化,就得能從外面把資料傳進去——這就是參數:
def greet(name):
print(f'哈囉,{name}!')
greet('小明')
greet('雅婷')哈囉,小明!
哈囉,雅婷!name 是參數,寫在定義的括號裡;呼叫時放進去的 '小明' 就會變成函式裡的 name。
但真正讓函式好用的是另一半:回傳值。函式不只能印東西,還能把「算完的結果交回來」給呼叫的人:
def average(scores):
return sum(scores) / len(scores)
math_scores = [88, 72, 95, 60, 78]
eng_scores = [70, 85, 91, 66, 80]
a = average(math_scores)
print(a)
print(round(average(eng_scores), 1))
print(f'數學平均 {average(math_scores):.1f},英文平均 {average(eng_scores):.1f}')作用範圍:函式裡的變數,外面看不到
這一段是函式最容易踩雷的地方,值得單獨看清楚。
count = 0
def add_one():
count = 100
print('函式內的 count =', count)
add_one()
print('函式外的 count =', count)函式內的 count = 100
函式外的 count = 0函式裡明明把 count 設成 100,外面卻還是 0。原因是在函式裡賦值,建立的是一個「只屬於這個函式」的新變數,跟外面那個同名的 count 是兩個不同的東西。函式執行完,裡面那個就消失了。
這種只在函式內部存在的變數叫區域變數(local variable),外面完全存取不到:
def calc():
temp = 999
calc()
print(temp)實戰:把成績統計程式重構成函式
回到開頭那段重複三次的程式。現在把它拆成幾個各司其職的函式:
def average(scores):
return sum(scores) / len(scores)
def top_student(names, scores):
best = max(scores)
return names[scores.index(best)], best
def pass_list(names, scores, line=70):
passed = []
for i in range(len(scores)):
if scores[i] >= line:
passed.append(names[i])
return passed
def report_subject(subject, names, scores):
print(f'--- {subject} ---')
print(f'人數 {len(scores)} 人,平均 {average(scores):.1f} 分')
name, score = top_student(names, scores)
print(f'最高分:{name} {score} 分')
passed = pass_list(names, scores)
print(f'及格 {len(passed)} 人:{passed}')
names = ['小明', '小華', '阿哲', '雅婷', '子豪']
math_scores = [88, 72, 95, 60, 78]
eng_scores = [70, 85, 91, 66, 80]
sci_scores = [90, 78, 84, 72, 95]
report_subject('數學', names, math_scores)
report_subject('英文', names, eng_scores)
report_subject('自然', names, sci_scores)