iT邦幫忙

2025 iThome 鐵人賽

DAY 20
0

前言

昨天在 Day19 我們介紹了函式的基礎操作,相信讀者們經過練習後,
對「函式的概念」已經比較熟悉了~

今天,我們要進入更實務的範例,順便提醒大家幾個容易踩雷的地方!
每個小標題(重點語法)都有實際範例,
幫助你理解「為什麼會這樣」,並知道「正確寫法」是什麼。

ㄧ、變數範圍(Scope)——LEGB 法則完整解析

變數在程式中「看得到」和「看不到」是有規則的。
Python 有個常見的記法叫 LEGB

  • Local(區域) — 函式或區塊內的變數
  • Enclosing(外部嵌套函式) — 嵌套函式外層的變數(closure)
  • Global(全域) — 模組層級的變數
  • Built-in(內建) — Python 內建名稱(如 lenmin

當你在某處查一個變數,Python 會先在 Local 找,
找不到就往外找 Enclosing、Global,最後才看 Built-in。

1. 區域範圍 (Local)

定義: 區域範圍指的是函式或方法內部的變數。
當你在函式內宣告一個變數,它只在這個函式內能使用。

特徵:

  • 函式一執行就建立區域範圍,函式結束後就銷毀。
  • 外部程式看不到這些區域變數。
def foo():
    x = 10   # x 是區域變數
    print("inside foo:", x)

foo()
print("outside:", x)  # ❌ 錯誤,x 在這裡不存在

‼️新手易錯提醒:不要在函式外直接呼叫區域變數!

輸出:
https://ithelp.ithome.com.tw/upload/images/20251004/201647210MvtsUAcrm.png

2.閉包範圍 (Enclosing)

定義: 閉包範圍是「函式內再定義函式」的情況下,外層函式的變數
特徵:

  • 閉包範圍只在函式嵌套(nested function)時會出現。
  • 內層函式會記住外層函式的變數,這種現象叫做「閉包(closure)」。

範例:

def outer():
    y = "outer variable"
    def inner():
        print("inner sees:", y)  # 可以看到外層函式的 y
    inner()

outer()

輸出:
https://ithelp.ithome.com.tw/upload/images/20251004/20164721AA9DYfHAjp.png

如果要在內層修改外層函式的變數,可以用 nonlocal

def outer():
    y = 0
    def inner():
        nonlocal y   # 修改外層變數
        y += 1
        print("inner y:", y)
    inner()
    inner()
outer()

‼️易錯提醒:沒有 nonlocal 就只能讀不能改外層變數喔!

輸出:
https://ithelp.ithome.com.tw/upload/images/20251004/2016472129sru6nngz.png

3. 全域範圍 (Global)

定義: 全域範圍是整個程式檔案的最外層,所有在函式外定義的變數都屬於全域變數。
特徵:

  • 任何函式都能讀取全域變數(只要名稱沒被區域變數覆蓋)。
  • 在函式內若要修改全域變數,必須用 global 關鍵字。
x = 100  # 全域變數

def show():
    print("x in function:", x)

show()
print("x outside:", x)

輸出:
https://ithelp.ithome.com.tw/upload/images/20251004/2016472108QwMQvZlE.png

如果要在函式內修改全域變數:

count = 0

def increase():
    global count
    count += 1

increase()
print("count:", count)  # 1

輸出:
https://ithelp.ithome.com.tw/upload/images/20251004/20164721f7VI0wkaEZ.png

範例:

balance = 100

def deposit(amount):
    global balance
    balance += amount

deposit(50)
print(balance)  # 會輸出150

‼️易錯提醒:忘記 global 就會創建一個新的區域變數,而不是改全域變數!

牛刀小試:全域變數vs區域變數

這邊用一題生活化的練習,來帶讀者們更能了解全域變數vs區域變數!

題目如下:

小華的家庭有一個「家庭零用錢罐」存放每個月的零用錢

(全域變數money = 1000元)

小華每次出去玩會帶一些錢在自己的錢包(區域變數),
如果錢包和罐子裡的變數名稱相同,錢包的錢會優先使用

money = 1000  # 家庭零用錢罐(全域)

def weekend_trip():
    money = 200  # 小華錢包裡的錢(區域)
    print("出去玩帶了多少錢:", money)

def shopping():
    print("逛街可以用家庭零用錢罐的錢:", money)

# 小華週末出去玩
weekend_trip()

# 平日逛街
shopping()

輸出:
https://ithelp.ithome.com.tw/upload/images/20251004/20164721iwLqd2IgEv.png

4.內建範圍 (Built-in)

定義:「內建範圍」是 Python 一打開就自帶的東西,
這些名稱你不用自己定義就能直接使用

換句話說,Python 啟動時就偷偷幫你 import builtins 了,
所以這些功能一直存在。(真的很方便!)

常見的內建函式(以數學相關為舉例)

  • abs(x):回傳絕對值
print(abs(-10))  # 10
  • round(x, n):四捨五入,n 表示小數點位數
print(round(3.14159, 2))  # 3.14

pow(x, y):計算 x 的 y 次方

print(pow(2, 3))  # 8

min()max():取最小值、最大值

print(min(3, 7, 1, 9))  # 1
print(max([3, 7, 1, 9]))  # 9

還有很多很多常見的內建函式!之前在Day1-Day19都有提到~
這邊就不在多介紹了!我會介紹之前沒有介紹過的概念給你們!

二、Lambda 運算式:一行的小函式

有時候函式只是臨時用一下,寫一個 def 太麻煩了,
這時候就可以用 lambda。lambda 就像「一次性小工具函式」,用完就丟。

語法:

lambda 參數: 運算式

範例:

add = lambda x, y: x + y
print(add(3, 5))  # 8

輸出:
https://ithelp.ithome.com.tw/upload/images/20251004/20164721cVDhxh2kKT.png

適合一行搞定的情況!但太複雜的邏輯,還是建議乖乖用 def 喔!!

1. lambda搭配 map():批量加工處理

你有一串東西,想全部加工一下,就用map()!
白話:它像一條「自動加工產線」。

nums = [1, 2, 3, 4]

# 每個數字平方
squares = list(map(lambda x: x**2, nums))
print(squares)

輸出:
https://ithelp.ithome.com.tw/upload/images/20251004/201647214oIjUBvJGh.png

2.搭配 filter():幫你篩選合格品

有時候你不需要全部,只要符合條件的,這時候用 filter()

白話:它像一個「把關篩子」。

nums = [1, 2, 3, 4, 5, 6]

# 篩出偶數
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens)

輸出:
https://ithelp.ithome.com.tw/upload/images/20251004/20164721fGGf4cniWd.png

3. lambda搭配 sorted():幫你照規則排好隊

sorted()可以幫你排序,也可以自訂規則。
白話:它像一個「整理員工」,而你告訴它照什麼規則排。

names = ["Amy", "John", "Michael", "Eve"]

# 依名字長度排序
sorted_names = sorted(names, key=lambda n: len(n))
print(sorted_names)

輸出:
https://ithelp.ithome.com.tw/upload/images/20251004/20164721wHKucZEa77.png

也可以反向排序喔:(把reverse設成True)


print(sorted(names, key=lambda n: len(n), reverse=True))

輸出:
https://ithelp.ithome.com.tw/upload/images/20251004/20164721lmuCStgc1K.png

三、math 函數:常用數學工具箱

Python 有個 math 模組,裡面放了一堆數學好用的函式。
math 就像隨身工具箱,遇到數學需求直接拿來用!!

記得要先匯入:

import math

範例:

print(math.sqrt(16))   # 平方根 = 4.0
print(math.pow(2, 3))  # 次方 = 8.0
print(math.factorial(5))  # 階乘 = 120
print(math.pi)         # 圓周率 3.141592653589793
print(math.e)          # 自然常數 e = 2.718281828...

輸出:
https://ithelp.ithome.com.tw/upload/images/20251004/20164721w6E57hnxph.png

四、實戰演練:ATM

功能說明

程式包含五個主要功能:

  1. 查詢餘額
    • 呼叫 check_balance()
    • 會印出目前帳戶餘額(TWD)
  2. 匯率計算
    • 呼叫 convert_currency()
    • 使用者可以輸入要計算的幣別(USD、JPY、EUR)
    • 程式會依照模擬匯率換算,並顯示換算後的金額
    • 特點:只是計算,不會真的扣款
  3. 存錢
    • 呼叫 deposit(amount)
    • 使用者輸入存款金額,會累加到 balance(全域變數)
    • 印出最新餘額
  4. 領錢
    • 呼叫 withdraw(amount)
    • 使用者輸入領出金額,程式會先檢查餘額是否足夠
    • 成功扣款後印出最新餘額
  5. 結束交易
    • 選擇 5 即可結束程式

完整程式碼:

# ===== 全域變數 =====
balance = 10000  # 初始帳戶餘額(台幣)

# ===== 函式區 =====
def check_balance():
    """查詢餘額(TWD)"""
    print(f"💰 目前帳戶餘額:{balance} TWD")

def convert_currency():
    """換匯,先顯示台幣餘額,再換成其他幣別"""
    print(f"💰 目前帳戶餘額:{balance} TWD")
    rates = {"USD": 0.033, "JPY": 5.0, "EUR": 0.03}  # 模擬匯率
    currency = input("輸入要計算的幣別 (USD/JPY/EUR):").upper()
    if currency in rates:
        converted = balance * rates[currency]
        print(f"💱 換算後餘額:{converted:.2f} {currency}")
    else:
        print("⚠️ 不支援的幣別")

def deposit(amount):
    """存錢"""
    global balance
    balance += amount
    print(f"✅ 已存入 {amount} 元,目前餘額:{balance} 元")

def withdraw(amount):
    """領錢"""
    global balance
    if amount > balance:
        print(f"⚠️ 餘額不足,目前餘額:{balance} 元")
    else:
        balance -= amount
        print(f"💰 已領出 {amount} 元,目前餘額:{balance} 元")

print("=== 歡迎使用鐵人ATM===")

while True:
    print("\n請選擇操作:")
    print("1. 查詢餘額")
    print("2. 匯率計算")
    print("3. 存錢")
    print("4. 領錢")
    print("5. 結束交易")

    choice = input("輸入數字選擇操作:")

    if choice == "1":
        check_balance()
    elif choice == "2":
        convert_currency()
    elif choice == "3":
        amount = float(input("輸入存入金額:"))
        deposit(amount)
    elif choice == "4":
        amount = float(input("輸入領出金額:"))
        withdraw(amount)
    elif choice == "5":
        print("感謝使用鐵人ATM!掰掰~")
        break
    else:
        print("⚠️ 輸入錯誤,請重新輸入")

輸出:
https://ithelp.ithome.com.tw/upload/images/20251004/20164721MRqybyCbGD.png

做完這個 ATM 小程式練習,你可以學到:

  1. 全域變數怎麼用、函式怎麼改
    • 像這裡的 balance,存錢、領錢、查餘額都會動它
    • 讓你理解「全域變數在哪裡可以用、怎麼修改」
  2. 函式封裝的重要性
    • 每個功能像「查餘額」「存錢」「領錢」「換匯」都打包成函式
    • 之後想用就呼叫,不用一直寫重複程式碼
  3. 參數傳遞
    • 存錢或領錢要帶金額參數,換匯要帶幣別
    • 幫助你理解「函式怎麼接收外部資料」
  4. 條件判斷與錯誤處理
    • if/elif/else 讓程式能處理使用者不同選擇
    • 預防輸入錯誤,讓程式更穩定
  5. 字典應用
    • 匯率用字典存,快速查詢、計算
    • 這種技巧生活化又實用,像查匯率、價格清單都能用
  6. 生活化思考程式
    • 用「ATM」模擬現實場景,程式就不再抽象
    • 讓你體會程式是幫你解決現實問題的工具

簡單說,做完這題,你不只會用函式,還會懂得 怎麼把程式拆成小功能、怎麼接收外部資料、怎麼控制流程,這些都是寫大型程式必備的基本功!

今日結語

辛苦啦!ㄧ下子就來到第20天了!!再十天就完賽啦~~

今天我們把 函式、變數範圍、lambda、math 模組、字典、條件判斷 都串起來,做了一個生活化的 ATM 範例。

小提醒:

  • 全域變數要小心修改
  • lambda 適合簡單運算,不要寫太複雜
  • 內建函式不要隨便當變數名

下次你寫程式,就可以試著把功能拆成小函式,
然後用全域變數或參數傳遞互動,程式會更乾淨、好維護!

那麼我們就明天見囉!!


上一篇
【Day19】打包你的程式碼,隨時呼叫!— 函式Function實戰指南(上)
下一篇
【Day21】類別與物件入門:讓你的程式更有組織力
系列文
Python 小白的逆襲:30 天從零到能教人的精華筆記,寫給迷惘的你與當年的我自己!24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言