DAY 26 函数专题1:函数定义与参数-2025.9.13
DAY 26 函数专题1:函数定义与参数
知识点回顾:
- 函数的定义
- 变量作用域:局部变量和全局变量
- 函数的参数类型:位置参数、默认参数、不定参数
- 传递参数的手段:关键词参数
- 传递参数的顺序:同时出现三种参数类型时
作业:
题目1:计算圆的面积
- 任务: 编写一个名为 calculate_circle_area 的函数,该函数接收圆的半径 radius 作为参数,并返回圆的面积。圆的面积 = π * radius² (可以使用 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 作为参数,并返回圆的面积。圆的面积 = π * radius² (可以使用 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 # 计算圆的面积:π * radius²area = 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必须是数字)
@浙大疏锦行