回文章列表
Python9 分鐘閱讀2026年6月21日

Python 函式 def 入門:同一段程式碼不要貼三次

#Python#函式#def#return#新手

文章目錄

先看一段很多人都寫過的程式。三個科目,各要算人數、平均、最高分:

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}')
78.6
78.4
數學平均 78.6,英文平均 78.4

return 的意思是「把這個值送回呼叫的地方,然後結束這個函式」。因為 average(...) 會變成一個實際的數字,你可以拿它去做任何事——存進變數、再丟給 round()、直接塞進 f-string。

print 和 return 是兩件事

這是新手最常混淆的地方。把上面的函式改成用 print 而不是 return:

def average_print(scores):
    print(sum(scores) / len(scores))


result = average_print([88, 72, 95, 60, 78])
print(result)
78.6
None

數字有印出來,但 result 是 None。因為 print 只是把東西顯示在畫面上,函式本身沒有交回任何值,Python 就給你 None(代表「什麼都沒有」)。

判準很單純:畫面要看到的用 print,程式要拿去繼續算的用 return。實務上絕大多數函式應該 return,因為一旦寫死成 print,你就沒辦法拿這個結果去做別的事了。

預設參數:讓某些輸入變成選填

參數可以先給一個預設值,呼叫時不傳就用預設的:

def report(scores, subject='科目'):
    print(f'{subject} 平均 {average(scores):.1f} 分')


report(math_scores)
report(math_scores, '數學')
科目 平均 78.6 分
數學 平均 78.6 分

有預設值的參數必須放在沒有預設值的後面,否則 Python 會直接報語法錯誤——因為它無法判斷你少傳的那個到底是誰。

作用範圍:函式裡的變數,外面看不到

這一段是函式最容易踩雷的地方,值得單獨看清楚。

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)
NameError: name 'temp' is not defined

反過來,函式讀得到外面的變數:

school = '中山國中'


def show_school():
    print('學校:', school)


show_school()
學校: 中山國中

所以規則是「讀得到,但改不到」——函式可以讀取外面的變數,但一旦在函式裡對它賦值,就會變成新建一個區域變數,而不是修改外面那個。

這聽起來很囉唆,但它其實是在保護你:因為函式裡的變數不會外洩,你在寫函式時可以放心用 i、temp、total 這些菜市場名,不必擔心撞到別的地方正在用的變數。這正是函式能被安心重複使用的原因。

(真的需要在函式裡修改外部變數時有 global 這個關鍵字,但初學階段請盡量不要用——那會讓程式變得難以追蹤是誰改了什麼。需要把結果帶出來,用 return 才是正解。)

實戰:把成績統計程式重構成函式

回到開頭那段重複三次的程式。現在把它拆成幾個各司其職的函式:

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)
--- 數學 ---
人數 5 人,平均 78.6 分
最高分:阿哲 95 分
及格 4 人:['小明', '小華', '阿哲', '子豪']
--- 英文 ---
人數 5 人,平均 78.4 分
最高分:阿哲 91 分
及格 4 人:['小明', '小華', '阿哲', '子豪']
--- 自然 ---
人數 5 人,平均 83.8 分
最高分:子豪 95 分
及格 5 人:['小明', '小華', '阿哲', '雅婷', '子豪']

三行 report_subject(...) 取代了原本三大段重複的程式碼。要加第四科,就再寫一行;要改平均的小數位數,只改 report_subject 裡的一個 .1f,三科同時生效。

有兩個地方值得多看一眼。

top_student 用 return names[...], best 一次回傳兩個值——Python 允許用逗號回傳多個值(實際上是包成一個 tuple),接的時候寫 name, score = top_student(...) 就會自動拆開。這在「一個函式要交回兩三個相關結果」時非常好用。

report_subject 裡面呼叫了 average、top_student、pass_list——函式可以呼叫別的函式。這是實務上組織程式的主要方式:小函式各做一件明確的事,大函式負責把它們串起來。你之後看到的任何一個像樣的專案,骨架都是這個形狀。

什麼時候該抽成函式

不必每三行就包一個函式,但遇到下面兩種情況就該動手:

同一段邏輯出現第二次的時候。第一次寫可以直接寫,第二次要複製貼上時就停下來抽成函式——這是最實用的判準,比任何理論都好記。

一段程式碼需要一句註解才說得清楚在做什麼的時候。那句註解通常就是函式的好名字。與其寫 # 找出最高分的學生,不如寫 def top_student(...),名字本身就是註解,而且不會像註解那樣改了程式忘了改。

寫到這裡,你已經有能力把前面幾篇的程式碼整理乾淨了——串列統計那支可以拆成函式,商品管理程式的選單與 CRUD 也可以,防呆那篇的 ask_choice() 其實就是一個函式。回頭把它們重構一遍,是很好的練習。

相關課程

Python 基礎入門

從零開始學習 Python 程式語言,掌握變數、流程控制、函式與模組化設計,建立扎實的程式設計基礎。

查看課程內容