DAY 26 函數專題1:函數定義與參數
知識點回顧:
- 函數的定義
- 變量作用域:局部變量和全局變量
- 函數的參數類型:位置參數、默認參數、不定參數
- 傳遞參數的手段:關鍵詞參數
- 傳遞參數的順序:同時出現三種參數類型時
作業:
題目1:計算圓的面積
- 任務: 編寫一個名為 calculate_circle_area 的函數,該函數接收圓的半徑 radius 作為參數,并返回圓的面積。圓的面積 = π * radius2 (可以使用 math.pi 作為 π 的值)
- 要求:函數接收一個位置參數 radius。計算半徑為5、0、-1時候的面積
- 注意點:可以采取try-except 使函數變得更加穩健,如果傳入的半徑為負數,函數應該返回 0 (或者可以考慮引發一個ValueError,但為了簡單起見,先返回0)。
題目2:計算矩形的面積
- 任務: 編寫一個名為 calculate_rectangle_area 的函數,該函數接收矩形的長度 length 和寬度 width 作為參數,并返回矩形的面積。
- 公式: 矩形面積 = length * width
- 要求:函數接收兩個位置參數 length 和 width。
- 函數返回計算得到的面積。
- 如果長度或寬度為負數,函數應該返回 0。
題目3:計算任意數量數字的平均值
- 任務: 編寫一個名為 calculate_average 的函數,該函數可以接收任意數量的數字作為參數(引入可變位置參數 (*args)),并返回它們的平均值。
- 要求:使用 *args 來接收所有傳入的數字。
- 如果沒有任何數字傳入,函數應該返回 0。
- 函數返回計算得到的平均值。
題目4:打印用戶信息
- 任務: 編寫一個名為 print_user_info 的函數,該函數接收一個必需的參數 user_id,以及任意數量的額外用戶信息(作為關鍵字參數)。
- 要求:
- user_id 是一個必需的位置參數。
- 使用 **kwargs 來接收額外的用戶信息。
- 函數打印出用戶ID,然后逐行打印所有提供的額外信息(鍵和值)。
- 函數不需要返回值
題目5:格式化幾何圖形描述
- 任務: 編寫一個名為 describe_shape 的函數,該函數接收圖形的名稱 shape_name (必需),一個可選的 color (默認 “black”),以及任意數量的描述該圖形尺寸的關鍵字參數 (例如 radius=5 對于圓,length=10, width=4 對于矩形)。
- 要求:shape_name 是必需的位置參數。
- color 是一個可選參數,默認值為 “black”。
- 使用 **kwargs 收集描述尺寸的參數。
- 函數返回一個描述字符串,格式如下:
- “A [color] [shape_name] with dimensions: [dim1_name]=[dim1_value], [dim2_name]=[dim2_value], …”如果 **kwargs 為空,則尺寸部分為 “with no specific dimensions.”
筆記:
1. 函數的定義:代碼的 “工具模塊”
函數是一段可重復使用的代碼塊,用來完成特定任務。定義函數就像制作一個 “工具”,需要時直接調用即可,避免重復寫相同代碼。
基本語法:
def 函數名(參數列表):"""函數說明文檔(可選)"""# 函數體(具體邏輯)return 返回值(可選)
例子:定義一個計算模型準確率的函數
def calculate_accuracy(y_true, y_pred):"""計算分類模型的準確率"""correct = sum(t == p for t, p in zip(y_true, y_pred))total = len(y_true)return correct / total if total != 0 else 0.0 # 避免除零錯誤
機器學習場景:在模型評估時,可重復調用這個函數計算訓練集、驗證集、測試集的準確率,無需重復寫計算邏輯。
2. 變量作用域:變量的 “活動范圍”
變量的作用域指變量能被訪問的代碼范圍,分為兩種:
類型 | 定義位置 | 訪問范圍 | 舉例 |
---|---|---|---|
局部變量 | 函數內部 | 僅在定義它的函數內部可訪問 | 函數calculate_accuracy 中的correct 、total |
全局變量 | 函數外部(整個程序頂層) | 整個程序(包括所有函數)都可訪問 | 在函數外定義的dataset_path = "data/train.csv" |
注意點:
- 函數內部可以讀取全局變量,但修改全局變量時需要用
global
聲明,否則會被當作局部變量處理。
# 全局變量
learning_rate = 0.01def set_learning_rate(new_lr):# 聲明要修改全局變量global learning_ratelearning_rate = new_lr # 此時修改的是全局變量set_learning_rate(0.001)
print(learning_rate) # 輸出 0.001(全局變量已被修改)
機器學習場景:全局變量可用于存儲整個程序都需要的配置(如數據路徑、全局種子),局部變量用于函數內部的臨時計算(如中間結果)。
3. 函數的參數類型:函數的 “輸入接口”
函數的參數是調用時傳入的 “原材料”,常見類型有 3 種:
(1)位置參數:必須按順序傳遞的參數
最基礎的參數類型,調用時必須按定義的順序傳遞,且數量要與定義一致。
# 定義:位置參數x, y
def add(x, y):return x + y# 調用:必須傳遞2個參數,順序對應x, y
print(add(3, 5)) # 輸出8(3傳給x,5傳給y)
(2)默認參數:有默認值的參數
定義時給參數設定默認值,調用時可以不傳遞(使用默認值),也可以傳遞新值覆蓋默認值。
# 定義:默認參數epochs(默認值10)
def train_model(X, y, epochs=10):print(f"用{epochs}輪訓練模型")# 調用1:不傳遞epochs,使用默認值10
train_model(X_train, y_train) # 輸出"用10輪訓練模型"# 調用2:傳遞epochs=20,覆蓋默認值
train_model(X_train, y_train, 20) # 輸出"用20輪訓練模型"
注意:默認參數必須放在位置參數后面(否則會報錯)。
(3)不定參數:接收任意數量的參數
當不確定需要傳遞多少個參數時使用,有兩種形式:
*args
:接收任意數量的位置參數,返回一個元組;**kwargs
:接收任意數量的關鍵字參數(見下文),返回一個字典。
# *args示例:計算多個特征的平均值
def mean_features(*args):# args是元組,例如傳入1,2,3時,args=(1,2,3)return sum(args) / len(args) if args else 0print(mean_features(1.2, 3.4, 2.1)) # 輸出(1.2+3.4+2.1)/3 = 2.233...# **kwargs示例:處理模型的多個超參數
def set_hyperparameters(** kwargs):# kwargs是字典,例如傳入lr=0.01, batch=32時,kwargs={"lr":0.01, "batch":32}for name, value in kwargs.items():print(f"超參數{name} = {value}")set_hyperparameters(lr=0.01, batch_size=32, epochs=50)
# 輸出:
# 超參數lr = 0.01
# 超參數batch_size = 32
# 超參數epochs = 50
機器學習場景:不定參數非常適合處理可變數量的輸入(如多個特征、多個超參數),例如模型集成時接收多個基礎模型。
4. 傳遞參數的手段:關鍵詞參數
調用函數時,通過參數名 = 值的形式傳遞參數,稱為關鍵詞參數。
優點:不需要嚴格按順序傳遞,代碼更易讀(尤其參數較多時)。
# 定義一個包含多個參數的函數
def build_model(input_dim, hidden_dim, output_dim, activation="relu"):print(f"輸入維度{input_dim},隱藏層{hidden_dim},輸出{output_dim},激活函數{activation}")# 用關鍵詞參數調用(順序可以打亂)
build_model(hidden_dim=128,input_dim=64,activation="tanh",output_dim=10
)
# 輸出:輸入維度64,隱藏層128,輸出10,激活函數tanh
機器學習場景:模型定義時參數往往很多(輸入維度、隱藏層大小、激活函數等),用關鍵詞參數傳遞能避免記混順序,減少錯誤。
5. 傳遞參數的順序:多種參數共存時的規則
當函數同時包含 ** 位置參數、默認參數、*args、kwargs時,定義和調用必須遵循固定順序,否則會報錯。
定義時的順序(從左到右):
- 位置參數
- 默認參數
*args
(不定位置參數)**kwargs
(不定關鍵字參數)
示例:符合順序的函數定義
def example_func(pos1, pos2, default1=0, default2=1, *args, **kwargs):print(f"位置參數:{pos1}, {pos2}")print(f"默認參數:{default1}, {default2}")print(f"不定位置參數*args:{args}")print(f"不定關鍵字參數**kwargs:{kwargs}")
調用時的對應規則:
- 位置參數必須先傳,且數量匹配;
- 默認參數可傳可不傳,傳時可按位置或關鍵詞;
*args
接收剩下的位置參數;**kwargs
接收剩下的關鍵詞參數。
# 調用示例
example_func(10, 20, # 位置參數pos1=10, pos2=2030, # 默認參數default1=30(默認2=1不變)40, 50, # 剩下的位置參數,被*args接收:args=(40,50)a=1, b=2 # 關鍵詞參數,被**kwargs接收:kwargs={"a":1, "b":2}
)
為什么要這樣規定順序?
- 位置參數是 “必須傳遞且順序敏感” 的,放在最前;
- 默認參數是 “可選且有默認值” 的,緊隨其后;
*args
和**kwargs
是 “可變數量” 的,放在最后避免歧義。
總結
- 函數是可重用的代碼塊,用
def
定義; - 變量作用域分局部(函數內)和全局(函數外),修改全局變量需用
global
; - 參數類型:位置參數(必傳)、默認參數(有默認值)、
*args
(不定位置)、**kwargs
(不定關鍵字); - 關鍵詞參數通過
參數名=值
傳遞,不依賴順序,更清晰;
多參數共存時,定義順序為:位置參數 → 默認參數 →*args
→**kwargs
。
這些是函數的核心基礎,掌握后能寫出更簡潔、靈活的代碼,尤其在機器學習中處理數據和模型時非常重要。
作業
題目1:計算圓的面積
- 任務: 編寫一個名為 calculate_circle_area 的函數,該函數接收圓的半徑 radius 作為參數,并返回圓的面積。圓的面積 = π * radius2 (可以使用 math.pi 作為 π 的值)
- 要求:函數接收一個位置參數 radius。計算半徑為5、0、-1時候的面積
- 注意點:可以采取try-except 使函數變得更加穩健,如果傳入的半徑為負數,函數應該返回 0 (或者可以考慮引發一個ValueError,但為了簡單起見,先返回0)。
import math def calculate_circle_area(radius):'''計算圓的面積參數:radius: 圓的半徑,必須是數字類型返回:圓的面積,若半徑為負數則返回0'''try: # 檢查半徑是否為負數if radius < 0:return 0 # 計算圓的面積:π * radius2area = math.pi * radius ** 2return areaexcept TypeError:# 處理非數字類型的輸入print("錯誤:半徑必須是數字類型")return 0# 測試不同半徑的情況
print(f"半徑為5的圓面積: {calculate_circle_area(5):.4f}")
print(f"半徑為0的圓面積: {calculate_circle_area(0)}")
print(f"半徑為-1的圓面積: {calculate_circle_area(-1)}")# 測試一個異常情況(非數字輸入)
print(f"非數字輸入的情況: {calculate_circle_area('invalid')}")
半徑為5的圓面積: 78.5398
半徑為0的圓面積: 0.0
半徑為-1的圓面積: 0
錯誤:半徑必須是數字類型
非數字輸入的情況: 0
題目2:計算矩形的面積
- 任務: 編寫一個名為 calculate_rectangle_area 的函數,該函數接收矩形的長度 length 和寬度 width 作為參數,并返回矩形的面積。
- 公式: 矩形面積 = length * width
- 要求:函數接收兩個位置參數 length 和 width。
- 函數返回計算得到的面積。
- 如果長度或寬度為負數,函數應該返回 0。
def calculate_rectangle_area(length,width):'''計算矩形的面積參數:length: 矩形的長度width:矩形的寬度返回:矩形的面積,若長度伙寬度為負數,則返回0'''try:if length < 0 :return 0 if width < 0 :return 0area = length * widthreturn areaexcept TypeError:# 處理非數字類型的輸入print("錯誤:參數必須是數字類型")return 0print(f'長為4,寬為2的矩形的面積為:{calculate_rectangle_area(4,2)}')
print(f'長為0,寬為2的矩形的面積為:{calculate_rectangle_area(0,2)}')
print(f'長為4,寬為0的矩形的面積為:{calculate_rectangle_area(4,0)}')
print(f'長為-1,寬為2的矩形的面積為:{calculate_rectangle_area(-1,2)}')
print(f'長為4,寬為-1的矩形的面積為:{calculate_rectangle_area(4,-1)}')# 測試一個異常情況(非數字輸入)
print(f"非數字輸入的情況: {calculate_rectangle_area('4',2)}")
長為4,寬為2的矩形的面積為:8
長為0,寬為2的矩形的面積為:0
長為4,寬為0的矩形的面積為:0
長為-1,寬為2的矩形的面積為:0
長為4,寬為-1的矩形的面積為:0
錯誤:參數必須是數字類型
非數字輸入的情況: 0
題目3:計算任意數量數字的平均值
- 任務: 編寫一個名為 calculate_average 的函數,該函數可以接收任意數量的數字作為參數(引入可變位置參數 (*args)),并返回它們的平均值。
- 要求:使用 *args 來接收所有傳入的數字。
- 如果沒有任何數字傳入,函數應該返回 0。
- 函數返回計算得到的平均值。
def calculate_average(*args):try:if len(args) == 0:return 0 total = sum(args)average = total/len(args)return averageexcept TypeError:print('錯誤:參數必須是數字類型')return 0 # 測試不同情況
print(f"沒有參數: {calculate_average()}") # 應該返回0
print(f"一個參數: {calculate_average(5)}") # 應該返回5.0
print(f"多個參數: {calculate_average(1, 2, 3, 4, 5)}") # 應該返回3.0
print(f"包含負數: {calculate_average(10, -5, 3)}") # 應該返回(10-5+3)/3 = 8/3 ≈ 2.666...
print(f"包含浮點數: {calculate_average(2.5, 3.5, 4.0)}") # 應該返回(2.5+3.5+4.0)/3 = 10/3 ≈ 3.333...# 測試異常情況(包含非數字)
print(f"包含非數字: {calculate_average(1, 2, 'three')}") # 應該捕獲錯誤并返回0
沒有參數: 0
一個參數: 5.0
多個參數: 3.0
包含負數: 2.6666666666666665
包含浮點數: 3.3333333333333335
錯誤:參數必須是數字類型
包含非數字: 0
題目4:打印用戶信息
- 任務: 編寫一個名為 print_user_info 的函數,該函數接收一個必需的參數 user_id,以及任意數量的額外用戶信息(作為關鍵字參數)。
- 要求:
- user_id 是一個必需的位置參數。
- 使用 **kwargs 來接收額外的用戶信息。
- 函數打印出用戶ID,然后逐行打印所有提供的額外信息(鍵和值)。
- 函數不需要返回值
def print_user_info(user_id, **kwargs):print(f'User ID :{user_id}')if kwargs:print('Additional Information:')for key, value in kwargs.items():print(f" {key}: {value}")else:print("No additional information provided.")# 測試函數
print("測試1:只提供user_id")
print_user_info(1001)
print("\n測試2:提供user_id和基本信息")
print_user_info(1002, name="Alice", age=30, email="alice@example.com")
print("\n測試3:提供更多信息")
print_user_info(1003, name="Bob", age=25, email="bob@example.com", occupation="Data Scientist", hobbies=["reading", "hiking", "coding"]
)
測試1:只提供user_id
User ID :1001
No additional information provided.
測試2:提供user_id和基本信息
User ID :1002
Additional Information:
name: Alice
age: 30
email: alice@example.com
測試3:提供更多信息
User ID :1003
Additional Information:
name: Bob
age: 25
email: bob@example.com
occupation: Data Scientist
hobbies: [‘reading’, ‘hiking’, ‘coding’]
題目5:格式化幾何圖形描述
- 任務: 編寫一個名為 describe_shape 的函數,該函數接收圖形的名稱 shape_name (必需),一個可選的 color (默認 “black”),以及任意數量的描述該圖形尺寸的關鍵字參數 (例如 radius=5 對于圓,length=10, width=4 對于矩形)。
- 要求:shape_name 是必需的位置參數。
- color 是一個可選參數,默認值為 “black”。
- 使用 **kwargs 收集描述尺寸的參數。
- 函數返回一個描述字符串,格式如下:
- “A [color] [shape_name] with dimensions: [dim1_name]=[dim1_value], [dim2_name]=[dim2_value], …”如果 **kwargs 為空,則尺寸部分為 “with no specific dimensions.”
def describe_shape(shape_name, color="black", **kwargs):"""生成幾何圖形的描述字符串(修復參數傳遞問題)參數:shape_name: 必需,圖形名稱(位置參數)color: 可選,圖形顏色,默認值為"black"**kwargs: 關鍵字參數,描述圖形的尺寸返回:格式化的圖形描述字符串"""try:# 驗證參數類型if not isinstance(shape_name, str):raise TypeError("shape_name must be a string (圖形名稱必須是字符串)")if not isinstance(color, str):raise TypeError("color must be a string (顏色必須是字符串)")# 構建基礎描述部分description = f"A {color} {shape_name} with "# 處理尺寸描述部分if kwargs:dimensions = []for dim_name, dim_value in kwargs.items():if not isinstance(dim_value, (int, float)):raise TypeError(f"Dimension {dim_name} must be a number (尺寸{dim_name}必須是數字)")dimensions.append(f"{dim_name}={dim_value}")description += f"dimensions: {', '.join(dimensions)}"else:description += "no specific dimensions."return descriptionexcept TypeError as e:return f"參數錯誤: {e}"except Exception as e:return f"意外錯誤: {e}"# 重新測試修復后的函數
print("測試1:基本用法(圓)")
print(describe_shape("circle", "red", radius=5)) # 正常傳遞colorprint("\n測試2:使用默認顏色(矩形)")
# 不傳遞color,使用默認值"black"
print(describe_shape("rectangle", length=10, width=4)) print("\n測試3:沒有尺寸參數(三角形)")
print(describe_shape("triangle", "blue")) # 傳遞color,無尺寸print("\n測試4:多個尺寸參數(長方體)")
print(describe_shape("cuboid", "green", length=5, width=3, height=2))print("\n測試5:異常情況(shape_name不是字符串)")
print(describe_shape(123, "yellow", radius=3)) # shape_name類型錯誤print("\n測試6:異常情況(尺寸不是數字)")
print(describe_shape("square", side="five")) # 尺寸值不是數字
測試1:基本用法(圓)
A red circle with dimensions: radius=5
測試2:使用默認顏色(矩形)
A black rectangle with dimensions: length=10, width=4
測試3:沒有尺寸參數(三角形)
A blue triangle with no specific dimensions.
測試4:多個尺寸參數(長方體)
A green cuboid with dimensions: length=5, width=3, height=2
測試5:異常情況(shape_name不是字符串)
參數錯誤: shape_name must be a string (圖形名稱必須是字符串)
測試6:異常情況(尺寸不是數字)
參數錯誤: Dimension side must be a number (尺寸side必須是數字)
@浙大疏錦行