2、Python函数设计与字典应用
学习目标:掌握代码模块化思维和键值对数据管理方法,建立可复用代码的设计理念
2.1 函数:让代码变得更聪明
> 什么是函数
想象一下,你有一个神奇的盒子,每次往里面放入原料,它都能按照固定的步骤制作出成品。比如放入面粉、鸡蛋、牛奶,它就能做出蛋糕。函数(Function) 就是这样一个神奇的盒子,你给它一些数据(原料),它按照预设的步骤处理,然后给你结果(成品)。
# 最简单的函数:不需要任何输入,只是执行一些操作
def say_hello():print("你好!欢迎学习Python")print("今天天气不错呢")# 调用函数(使用这个神奇盒子)
say_hello()
# 输出:
# 你好!欢迎学习Python
# 今天天气不错呢
> 为什么要使用函数
如果没有函数,我们每次想打招呼都要重复写相同的代码:
# 没有函数的重复代码
print("你好!欢迎学习Python")
print("今天天气不错呢")print("你好!欢迎学习Python")
print("今天天气不错呢")print("你好!欢迎学习Python")
print("今天天气不错呢")
有了函数,我们只需要写一次,然后重复调用:
# 定义一次,多次使用
def say_hello():print("你好!欢迎学习Python")print("今天天气不错呢")# 多次调用
say_hello() # 第一次打招呼
say_hello() # 第二次打招呼
say_hello() # 第三次打招呼
核心优势:函数让我们的代码更加整洁,避免重复,并且如果需要修改,只需要改一个地方。
2.2 带参数的函数:让盒子更灵活
> 函数参数的基本概念
刚才的打招呼函数只能说固定的话,不够灵活。如果我们想对不同的人说不同的招呼语怎么办?这就需要 参数(Parameter) 了。
# 带参数的函数
def greet_person(name):print(f"你好,{name}!")print("欢迎来到Python世界")# 调用时传入不同的参数
greet_person("小明") # 你好,小明!欢迎来到Python世界
greet_person("小红") # 你好,小红!欢迎来到Python世界
greet_person("老师") # 你好,老师!欢迎来到Python世界
> 多个参数的函数
函数可以接收多个参数,就像做菜需要多种原料一样:
# 计算两个数相加的函数
def add_numbers(first_number, second_number):result = first_number + second_numberprint(f"{first_number} + {second_number} = {result}")# 使用函数
add_numbers(5, 3) # 5 + 3 = 8
add_numbers(10, 7) # 10 + 7 = 17
add_numbers(100, 200) # 100 + 200 = 300
> 默认参数:给函数设置默认值
有时候我们希望某个参数有一个默认值,这样调用函数时可以选择性地提供参数:
# 带默认参数的问候函数
def greet_with_time(name, time="上午"):print(f"{time}好,{name}!")# 不同的调用方式
greet_with_time("小明") # 上午好,小明!(使用默认值)
greet_with_time("小红", "下午") # 下午好,小红!(指定时间)
greet_with_time("小刚", "晚上") # 晚上好,小刚!(指定时间)
> 关键字参数:让调用更清楚
当函数有多个参数时,我们可以指定参数的名字,这样调用更清楚:
# 介绍个人信息的函数
def introduce_person(name, age, city, hobby):print(f"大家好,我是{name}")print(f"今年{age}岁")print(f"来自{city}")print(f"爱好是{hobby}")# 位置参数调用(按顺序传递)
introduce_person("小明", 20, "北京", "读书")# 关键字参数调用(指定参数名,顺序可以改变)
introduce_person(city="上海", name="小红", hobby="画画", age=22)# 混合调用(前面用位置参数,后面用关键字参数)
introduce_person("小刚", 25, hobby="游泳", city="深圳")
2.3 函数的返回值:让盒子给出结果
> 什么是返回值
之前我们的函数只是打印信息,但很多时候我们希望函数计算出结果并返回给我们,这样我们可以用这个结果做其他事情。返回值(Return Value) 就是函数给我们的答案。
# 计算圆形面积的函数
def calculate_circle_area(radius):pi = 3.14159area = pi * radius * radiusreturn area # 把计算结果返回给调用者# 使用返回值
room_area = calculate_circle_area(5)
print(f"房间面积是:{room_area}平方米")garden_area = calculate_circle_area(3)
print(f"花园面积是:{garden_area}平方米")# 可以直接在其他计算中使用返回值
total_area = calculate_circle_area(4) + calculate_circle_area(2)
print(f"总面积是:{total_area}平方米")
> 返回多个值
Python的函数可以同时返回多个值,这很方便:
# 同时计算圆形的周长和面积
def calculate_circle_info(radius):pi = 3.14159area = pi * radius * radiuscircumference = 2 * pi * radiusreturn area, circumference # 返回两个值# 接收多个返回值
my_area, my_circumference = calculate_circle_info(5)
print(f"面积:{my_area}")
print(f"周长:{my_circumference}")
> 条件返回
函数可以根据不同条件返回不同的值:
# 根据分数判断等级
def get_grade_level(score):if score >= 90:return "优秀"elif score >= 80:return "良好"elif score >= 60:return "及格"else:return "不及格"# 使用函数
student_score = 85
level = get_grade_level(student_score)
print(f"分数{student_score}对应的等级是:{level}")# 可以直接在条件判断中使用
if get_grade_level(95) == "优秀":print("这个学生成绩很棒!")
2.4 字典:更智能的数据管理方式
> 什么是字典
到目前为止,我们用列表来存储多个数据。但列表有个问题:我们只能用数字位置来找数据(比如第0个、第1个)。字典(Dictionary) 就像现实中的电话簿,你可以用名字(而不是页码)来找电话号码。
# 列表的局限性
student_info_list = ["小明", 20, "北京", "计算机"]
# 要记住:0是姓名,1是年龄,2是城市,3是专业# 字典的优势
student_info_dict = {"姓名": "小明","年龄": 20,"城市": "北京","专业": "计算机"
}
# 可以直接用有意义的名字来访问数据
> 字典的基本操作
# 创建字典
person = {"name": "张三","age": 25,"city": "上海","job": "程序员"
}# 访问字典中的值
print(f"姓名:{person['name']}") # 姓名:张三
print(f"年龄:{person['age']}岁") # 年龄:25岁
print(f"城市:{person['city']}") # 城市:上海# 修改字典中的值
person["age"] = 26 # 改年龄
person["city"] = "深圳" # 换城市
print(f"更新后的年龄:{person['age']}") # 更新后的年龄:26# 添加新的键值对
person["phone"] = "138-0000-0000" # 添加电话
person["email"] = "zhangsan@qq.com" # 添加邮箱print(person) # 查看完整字典
> 安全地访问字典
有时候我们要找的键可能不存在,直接访问会出错。Python提供了安全的方法:
student = {"name": "李四","age": 22,"major": "数学"
}# 危险的访问方式(如果键不存在会出错)
# print(student["phone"]) # 这行会报错,因为没有"phone"这个键# 安全的访问方式
phone = student.get("phone", "未提供") # 如果没有phone键,返回"未提供"
email = student.get("email", "无邮箱") # 如果没有email键,返回"无邮箱"print(f"电话:{phone}") # 电话:未提供
print(f"邮箱:{email}") # 邮箱:无邮箱# 检查键是否存在
if "phone" in student:print(f"电话:{student['phone']}")
else:print("这个学生没有留电话")
> 遍历字典
我们可以遍历字典中的所有信息:
student_info = {"姓名": "王五","年龄": 23,"专业": "英语","成绩": 88,"城市": "广州"
}print("学生信息:")
print("-" * 20)# 遍历字典的键和值
for key, value in student_info.items():print(f"{key}:{value}")# 只遍历键
print("\n所有的信息类别:")
for key in student_info.keys():print(f"- {key}")# 只遍历值
print("\n所有的信息内容:")
for value in student_info.values():print(f"- {value}")
2.5 字典与列表的对比选择
> 什么时候用列表,什么时候用字典
特点 | 列表(List) | 字典(Dictionary) |
---|---|---|
数据访问 | 用位置索引(0,1,2…) | 用有意义的键名 |
数据特点 | 通常是同类型的数据 | 通常是不同属性的数据 |
使用场景 | 存储一组相似的东西 | 存储一个事物的多个属性 |
举例 | 一班所有学生的姓名 | 一个学生的详细信息 |
# 适合用列表的情况:存储同类型的多个数据
class_names = ["小明", "小红", "小刚", "小丽"] # 一个班的学生名字
monthly_sales = [1200, 1500, 1800, 1600] # 每月销售额
daily_temperatures = [25, 27, 23, 26, 24] # 每日温度# 适合用字典的情况:存储一个对象的多个属性
student_profile = {"name": "小明","age": 20,"grade": 85,"major": "计算机","phone": "138-0000-0000"
}product_info = {"name": "苹果","price": 5.5,"stock": 100,"category": "水果","supplier": "果园农场"
}
> 复杂数据结构的组合使用
在实际应用中,我们经常需要组合使用列表和字典:
# 存储多个学生的信息:列表包含字典
students_class = [{"name": "小明","age": 20,"scores": [85, 92, 78] # 字典中也可以包含列表},{"name": "小红", "age": 19,"scores": [90, 87, 95]},{"name": "小刚","age": 21,"scores": [76, 82, 88]}
]# 访问复杂结构中的数据
print(f"第一个学生的名字:{students_class[0]['name']}")
print(f"小红的第一科成绩:{students_class[1]['scores'][0]}")# 遍历所有学生的信息
for student in students_class:name = student["name"]age = student["age"]scores = student["scores"]average_score = sum(scores) / len(scores)print(f"{name}({age}岁):平均分 {average_score:.1f}")
2.6 实战项目:学生信息管理系统
现在让我们综合运用函数和字典,制作一个完整的学生信息管理系统:
def create_student_system():"""创建学生信息管理系统"""# 用列表存储所有学生(每个学生是一个字典)students_database = []def add_student(name, age, grade, subjects):"""添加新学生的函数"""new_student = {"name": name,"age": age,"grade": grade,"subjects": subjects,"average_score": sum(subjects) / len(subjects)}students_database.append(new_student)print(f"成功添加学生:{name}")return new_studentdef find_student(name):"""查找学生的函数"""for student in students_database:if student["name"] == name:return studentreturn Nonedef display_student(student):"""显示学生信息的函数"""if student:print(f"\n学生姓名:{student['name']}")print(f"年龄:{student['age']}岁")print(f"年级:{student['grade']}")print(f"各科成绩:{student['subjects']}")print(f"平均分:{student['average_score']:.1f}")# 根据平均分判断等级level = get_performance_level(student['average_score'])print(f"成绩等级:{level}")else:print("未找到该学生")def get_performance_level(average_score):"""判断成绩等级的函数"""if average_score >= 90:return "优秀"elif average_score >= 80:return "良好"elif average_score >= 60:return "及格"else:return "需要加油"def display_all_students():"""显示所有学生的函数"""if not students_database:print("目前没有学生信息")returnprint("\n" + "="*40)print("所有学生信息汇总")print("="*40)for student in students_database:print(f"{student['name']:<6} | "f"{student['age']:2d}岁 | "f"{student['grade']:6} | "f"平均分:{student['average_score']:5.1f}")def get_class_statistics():"""获取班级统计信息的函数"""if not students_database:return "暂无数据"all_averages = [student['average_score'] for student in students_database]class_average = sum(all_averages) / len(all_averages)highest_score = max(all_averages)lowest_score = min(all_averages)# 找到最高分和最低分的学生best_student = ""worst_student = ""for student in students_database:if student['average_score'] == highest_score:best_student = student['name']if student['average_score'] == lowest_score:worst_student = student['name']return {"class_average": class_average,"highest_score": highest_score,"lowest_score": lowest_score,"best_student": best_student,"worst_student": worst_student,"total_students": len(students_database)}# 演示系统功能print("学生信息管理系统启动")print("="*30)# 添加一些示例学生add_student("张三", 18, "高二1班", [85, 92, 78, 88])add_student("李四", 17, "高二1班", [90, 87, 95, 89])add_student("王五", 18, "高二1班", [76, 82, 88, 84])add_student("赵六", 17, "高二1班", [95, 98, 92, 96])print("\n功能演示:")print("-"*20)# 查找并显示特定学生print("1. 查找学生信息:")target_student = find_student("李四")display_student(target_student)# 显示所有学生print("\n2. 所有学生列表:")display_all_students()# 显示统计信息print("\n3. 班级统计信息:")stats = get_class_statistics()print("-"*30)print(f"班级总人数:{stats['total_students']}人")print(f"班级平均分:{stats['class_average']:.1f}")print(f"最高平均分:{stats['highest_score']:.1f}({stats['best_student']})")print(f"最低平均分:{stats['lowest_score']:.1f}({stats['worst_student']})")return students_database# 运行学生管理系统
student_data = create_student_system()
> 项目技术要点分析
这个学生信息管理系统展示了函数和字典的强大组合:
模块化设计思维:每个功能都封装在独立的函数中,便于维护和扩展。添加学生、查找学生、显示信息等功能都是独立的模块,可以单独调用和测试。
数据结构的合理选择:使用列表存储多个学生,每个学生用字典存储详细信息。这种结构既便于遍历所有学生,又便于访问具体学生的属性。
函数参数与返回值的实践:不同函数采用不同的参数设计,有些返回处理结果,有些返回布尔值,有些不返回值只执行操作。这体现了函数设计的灵活性。
错误处理机制:在查找学生时考虑了找不到的情况,在统计信息时检查了空数据库的情况,提高了程序的健壮性。
2.7 学习建议与进阶练习
> 巩固练习建议
- 函数基础练习:编写计算器函数,包含加减乘除四个功能
- 参数练习:创建个人介绍函数,支持默认参数和关键字参数
- 字典练习:制作家庭成员信息字典,包含姓名、年龄、职业等信息
- 综合练习:扩展学生管理系统,添加删除学生、修改信息等功能
> 编程思维提升
模块化思考:遇到复杂问题时,首先考虑如何分解为小的功能模块,每个模块用一个函数实现。这样的代码更容易理解、测试和维护。
数据结构选择:根据数据的性质和使用方式选择合适的结构。如果需要通过有意义的名字访问数据,优先考虑字典;如果是一组相似的数据,优先考虑列表。
函数设计原则:每个函数应该只做一件事情,并且做好这件事。函数名要清楚地表达功能,参数设计要合理,返回值要有明确的含义。
错误预防意识:在编写函数时,要考虑可能出现的异常情况,比如参数为空、找不到数据等,提前做好处理。
附录:专业术语表
函数(Function):完成特定功能的代码块,可以接收参数并返回结果,实现代码的重复使用
参数(Parameter):函数接收的输入数据,用于定制函数的行为和处理过程
默认参数(Default Parameter):函数定义时为参数设置的默认值,调用时可以不提供该参数
关键字参数(Keyword Arguments):调用函数时通过参数名指定参数值的方式,提高代码可读性
返回值(Return Value):函数执行完成后返回给调用者的结果数据
字典(Dictionary):基于键值对存储数据的结构,通过有意义的键名访问对应的值
键值对(Key-Value Pair):字典中的基本存储单元,由唯一的键和对应的值组成
模块化编程(Modular Programming):将复杂问题分解为独立功能模块的编程方法,提高代码复用性和维护性