2025年9月30日 星期二

[水井USR創新教材]Python一下用魚菜共生模擬小例子來說明函式的進階概念

 


以下是由ChatGPT協助生成:

在 Python 裡,函式本身也是一種物件,可以:

  • 指派給變數

  • 放進資料結構(如 list)

  • 當作參數傳遞

範例一:函式視為物件(Function as Object)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
def carbon_calc(area):
    """計算單位面積月減碳量(假設固定係數)"""
    return round(area * 0.12, 2)

def water_calc(area):
    """計算單位面積月節水量"""
    return round(area * 0.08, 2)

# 函式指派給變數
c_func = carbon_calc
print("函式當變數使用:", c_func(10))

# 函式放入清單
calculators = [carbon_calc, water_calc]
for func in calculators:
    print(f"{func.__name__}{func(5)}")

# 函式當作參數傳遞
def apply_to_area(func, area):
    return func(area)

print("傳遞函式當參數:", apply_to_area(water_calc, 8))

執行結果:
函式當變數使用: 1.2
carbon_calc:0.6
water_calc:0.4
傳遞函式當參數: 0.64

📌 重點:

  • 函式本身可以像資料一樣被傳遞與儲存。

  • 為後面 closure 與 decorator 打基礎。


匿名函式適合用於小型、一次性邏輯,特別是排序、映射或高階函式中。
範例二:Lambda 函式(匿名函式)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# lambda 版本的碳排計算
carbon_lambda = lambda area: round(area * 0.15, 2)
print("lambda 計算碳排:", carbon_lambda(10))

# lambda 用於 list 遍歷
areas = [3.3, 5.5, 10]
results = list(map(lambda a: round(a * 0.1, 2), areas))
print("lambda map 結果:", results)

# lambda 與 sorted 搭配
ponds = [("A池", 5), ("B池", 10), ("C池", 3)]
sorted_ponds = sorted(ponds, key=lambda x: x[1], reverse=True)
print("依面積排序魚池:", sorted_ponds)

執行結果:
lambda 計算碳排: 1.5
lambda map 結果: [0.33, 0.55, 1.0]
依面積排序魚池: [('B池', 10), ('A池', 5), ('C池', 3)]

📌 重點:

  • lambda = 匿名函式,可快速撰寫簡單邏輯。

  • 適合與 map / filter / sorted 等搭配。

產生器是用 yield 逐步產生資料,適合處理每月模擬資料流👇
範例三:產生器(Generator)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import random

def aquaponics_generator(months, area=3.3058):
    """每次呼叫 yield 一個月份的模擬資料"""
    for month in range(1, months + 1):
        seasonal_factor = 1.2 if 6 <= (month % 12 or 12) <= 8 else 1.0
        carbon = area * 0.12 * seasonal_factor + random.uniform(-0.5, 0.5)
        water = area * 0.08 * seasonal_factor + random.uniform(-0.05, 0.05)
        yield month, round(carbon, 2), round(water, 2)

# 使用 generator
sim = aquaponics_generator(6)
for m, c, w in sim:
    print(f"第 {m} 月:減碳 {c} kg,節水 {w} m³")

執行結果:
第 1 月:減碳 0.73 kg,節水 0.24 m³
第 2 月:減碳 -0.07 kg,節水 0.3 m³
第 3 月:減碳 0.78 kg,節水 0.25 m³
第 4 月:減碳 -0.03 kg,節水 0.3 m³
第 5 月:減碳 0.88 kg,節水 0.24 m³
第 6 月:減碳 0.78 kg,節水 0.36 m³

📌 重點:

  • yield 會回傳一筆資料,但保留函式狀態。

  • 適合大量資料的逐筆處理。


內部函式就是在函式中再定義函式,可以封裝邏輯,避免汙染全域命名空間👇
範例四:內部函式(Inner Function)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def simulate_one_year(area):
    """外部函式:包一年模擬"""

    def simulate_month(m):
        """內部函式:只在一年模擬裡用"""
        factor = 1.2 if 6 <= (m % 12 or 12) <= 8 else 1.0
        return round(area * 0.1 * factor, 2)

    results = []
    for month in range(1, 13):
        results.append(simulate_month(month))
    return results

print("一年模擬結果:", simulate_one_year(5))

執行結果:
一年模擬結果: [0.5, 0.5, 0.5, 0.5, 0.5, 0.6, 0.6, 0.6, 0.5, 0.5, 0.5, 0.5]

📌 重點:

  • simulate_month 只存在 simulate_one_year 裡。

  • 有助於模組化程式與邏輯分層。

閉包的意思是要讓內部函式「記住」外部函式的變數,即使外部函式已經結束👇
範例五:Closure 函式(閉包)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
def make_carbon_calculator(base_factor):
    """回傳一個記住 base_factor 的函式"""
    def calculator(area):
        return round(area * base_factor, 2)
    return calculator

# 建立兩種不同設定的計算器
summer_calc = make_carbon_calculator(0.15)  # 夏季
winter_calc = make_carbon_calculator(0.10)  # 冬季

print("夏季碳排:", summer_calc(10))
print("冬季碳排:", winter_calc(10))

執行結果:
夏季碳排: 1.5
冬季碳排: 1.0

📌 重點:

  • 閉包讓函式能夠「攜帶環境」。

  • 很適合製作客製化計算器或累積器。


裝飾器可用於增強函式,例如:

  • 日誌紀錄

  • 輸入檢查

  • 統計運行時間

範例六:Decorator(裝飾器)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import functools

def log_simulation(func):
    """裝飾器:在模擬前後加上日誌"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("👉 開始模擬")
        result = func(*args, **kwargs)
        print("✅ 模擬完成")
        return result
    return wrapper

@log_simulation
def run_simulation(months):
    for m in range(1, months + 1):
        print(f"模擬第 {m} 月...")
    return "模擬結束"

print(run_simulation(3))

執行結果:
👉 開始模擬
模擬第 1 月...
模擬第 2 月...
模擬第 3 月...
✅ 模擬完成
模擬結束

📌 重點:

  • Decorator 是高階函式,輸入函式,回傳包裝過的函式。

  • @decorator_name 是語法糖,等同於 func = decorator(func)

沒有留言:

張貼留言