Python全栈(基础篇)——Day07:后端内容(函数的参数+递归函数+实战演示+每日一题)
目录
一、函数的参数——让函数真正"活"起来
1.1 为什么需要函数参数?
1.2 参数的基本概念
二、位置参数——最基础的参数类型
2.1 什么是位置参数?
2.2 位置参数的详细示例
2.3 位置参数的重要特性
三、默认参数——让函数更智能
3.1 什么是默认参数?
3.2 默认参数的详细示例
3.3 默认参数的注意事项
四、关键字参数——明确指定参数值
4.1 什么是关键字参数?
4.2 关键字参数的详细示例
4.3 关键字参数的优势
五、可变参数——处理不确定数量的参数
5.1 什么是可变参数?
5.2 *args 的详细示例
5.3 **kwargs 的详细示例
六、递归函数——函数调用自己
6.1 什么是递归函数?
6.2 递归函数的经典示例
6.3 递归的注意事项
七、实战演示——综合应用案例
7.1 实战项目一:智能计算器系统
7.2 实战项目二:递归目录树生成器
八、每日一题:学生成绩管理系统
题目要求
评分标准
提示
九、结语
嘿,朋友们!👋
我是你们的学习伙伴,继续带着大家探索Python的奇妙世界!昨天我们学习了函数的基本概念,今天我们要深入探讨函数的参数和递归函数这两个非常重要的主题。
如果你觉得我的讲解方式对你有帮助,或者喜欢我这种"把复杂变简单"的教学风格,欢迎来我的小窝坐坐~
我的技术博客:python全栈蛇行者-CSDN博客
那里有更多精心整理的学习笔记、实战项目,还有我在学习中踩过的坑和总结的经验。
专栏订阅也不容错过哦!我会持续更新这个Python全栈系列,从基础到实战,手把手带你走进编程的世界。订阅之后,新文章会第一时间推送到你面前,再也不用担心错过精彩内容啦!
好啦,让我们开始今天的学习之旅吧!
一、函数的参数——让函数真正"活"起来
1.1 为什么需要函数参数?
昨天我们学习了无参数函数,它们就像固定的菜谱,每次做出来的菜都一样。但现实世界中,我们需要的是能够根据输入不同而产生不同结果的函数。
生活中的类比:
-
咖啡机:你可以选择咖啡浓度、杯数、是否加糖
-
导航软件:你输入起点和终点,它给你规划路线
-
计算器:你输入数字和运算符,它给你计算结果
编程中的参数就是函数的"输入控制",让函数变得更加灵活和强大。
1.2 参数的基本概念
让我们通过对比来理解参数的重要性:
没有参数的函数(固定功能):
def calculate_area_fixed():"""计算固定半径的圆面积"""radius = 5 # 固定值area = 3.14 * radius * radiusreturn area
# 每次调用都得到相同的结果
print(calculate_area_fixed()) # 输出: 78.5
print(calculate_area_fixed()) # 输出: 78.5
有参数的函数(灵活功能):
def calculate_area_flexible(radius):"""计算任意半径的圆面积"""area = 3.14 * radius * radiusreturn area
# 根据不同的输入得到不同的结果
print(calculate_area_flexible(5)) # 输出: 78.5
print(calculate_area_flexible(10)) # 输出: 314.0
print(calculate_area_flexible(2)) # 输出: 12.56
通过这个简单的对比,我们可以看到参数让函数从"死板"变得"灵活"。现在函数可以根据我们提供的不同半径值来计算对应的面积,这才是函数真正强大的地方!
二、位置参数——最基础的参数类型
2.1 什么是位置参数?
位置参数是最简单、最常用的参数类型。它们按照定义时的顺序进行传递和接收。
基本语法:
def 函数名(参数1, 参数2, 参数3, ...):# 函数体return 返回值
2.2 位置参数的详细示例
示例1:简单的计算函数
def add_numbers(a, b):"""计算两个数字的和参数:a: 第一个数字b: 第二个数字返回:两个数字的和"""result = a + breturn result
# 调用函数
sum1 = add_numbers(10, 20)
sum2 = add_numbers(5, 8)
sum3 = add_numbers(-3, 7)
print(f"10 + 20 = {sum1}") # 输出: 10 + 20 = 30
print(f"5 + 8 = {sum2}") # 输出: 5 + 8 = 13
print(f"-3 + 7 = {sum3}") # 输出: -3 + 7 = 4
示例2:个人信息处理函数
def create_user_profile(name, age, city, hobby):"""创建用户个人资料参数:name: 用户名age: 年龄city: 城市hobby: 爱好返回:格式化的个人资料字符串"""profile = f"""🎯 用户资料------------👤 姓名: {name}🎂 年龄: {age}🏙️ 城市: {city}❤️ 爱好: {hobby}"""return profile
# 调用函数(注意参数顺序!)
user1 = create_user_profile("张三", 25, "北京", "编程")
user2 = create_user_profile("李四", 30, "上海", "旅行")
user3 = create_user_profile("王五", 22, "广州", "摄影")
print(user1)
print(user2)
print(user3)
2.3 位置参数的重要特性
1. 顺序必须匹配
def introduce_person(name, age, profession):"""介绍一个人"""return f"{name}今年{age}岁,是一名{profession}。"
# 正确的调用顺序
correct = introduce_person("小明", 25, "工程师")
print(correct) # 输出: 小明今年25岁,是一名工程师。
# 错误的调用顺序(会产生奇怪的结果)
wrong = introduce_person("工程师", "小明", 25)
print(wrong) # 输出: 工程师今年小明岁,是一名25。
2. 参数数量必须一致
def greet_person(greeting, name):"""向某人打招呼"""return f"{greeting}, {name}!"
# 正确的调用
print(greet_person("你好", "世界")) # 输出: 你好, 世界!
# 错误的调用 - 参数太少
# print(greet_person("你好")) # 这会报错!
# 错误的调用 - 参数太多
# print(greet_person("你好", "世界", "!")) # 这会报错!
位置参数是函数参数的基础,理解它们的特性非常重要。记住:位置、位置、还是位置! 参数的位置决定了它们被如何接收和使用。
三、默认参数——让函数更智能
3.1 什么是默认参数?
默认参数允许我们为参数提供默认值,这样在调用函数时,如果省略这些参数,就会使用默认值。
基本语法:
def 函数名(参数1=默认值1, 参数2=默认值2, ...):# 函数体return 返回值
3.2 默认参数的详细示例
示例1:智能问候函数
def greet(name="朋友", greeting="你好", punctuation="!"):"""智能问候函数参数:name: 要问候的人名,默认为"朋友"greeting: 问候语,默认为"你好" punctuation: 标点符号,默认为"!"返回:完整的问候语"""return f"{greeting}{punctuation} {name}{punctuation}"
# 各种调用方式
print(greet()) # 使用所有默认值
print(greet("小明")) # 只提供名字
print(greet("小红", "早上好")) # 提供名字和问候语
print(greet("小刚", "晚安", "~")) # 提供所有参数
示例2:配置系统设置函数
def configure_system(theme="light", language="zh-CN", font_size=14):"""配置系统设置参数:theme: 主题,默认为"light"language: 语言,默认为"zh-CN"font_size: 字体大小,默认为14"""configuration = {'主题': theme,'语言': language, '字体大小': f"{font_size}px"}print("⚙️ 系统配置:")for key, value in configuration.items():print(f" {key}: {value}")return configuration
# 各种调用方式
print("=== 默认配置 ===")
configure_system()
print("\n=== 暗色主题配置 ===")
configure_system(theme="dark")
print("\n=== 英文界面配置 ===")
configure_system(language="en-US", font_size=16)
3.3 默认参数的注意事项
1. 默认参数的位置
# 正确的定义:默认参数在必需参数后面
def correct_function(required1, required2, optional1="默认", optional2="默认"):pass
# 错误的定义:默认参数在必需参数前面
# def wrong_function(optional1="默认", required1, required2):
# pass # 这会报错!
2. 默认参数的求值时机
def add_item_to_list(item, my_list=[]):"""注意:默认参数在函数定义时求值,而不是在调用时!"""my_list.append(item)return my_list
# 这可能不是你想要的行为!
print(add_item_to_list("苹果")) # 输出: ['苹果']
print(add_item_to_list("香蕉")) # 输出: ['苹果', '香蕉'] - 啊哦!
# 正确的做法:使用None作为默认值
def add_item_to_list_correct(item, my_list=None):if my_list is None:my_list = []my_list.append(item)return my_list
print(add_item_to_list_correct("苹果")) # 输出: ['苹果']
print(add_item_to_list_correct("香蕉")) # 输出: ['香蕉'] - 正确!
默认参数让我们的函数变得更加智能和灵活。它们为参数提供了"后备值",让函数在缺少某些输入时仍然能够正常工作。
四、关键字参数——明确指定参数值
4.1 什么是关键字参数?
关键字参数允许我们通过参数名来传递值,这样可以不按照参数定义的顺序传递参数。
基本语法:
函数名(参数名1=值1, 参数名2=值2, ...)
4.2 关键字参数的详细示例
示例1:用户注册函数
def register_user(username, email, password, age=None, city=None):"""用户注册函数参数:username: 用户名(必需)email: 邮箱(必需)password: 密码(必需)age: 年龄,可选city: 城市,可选 """user_info = {'用户名': username,'邮箱': email,'密码': "***" + password[-3:], # 只显示最后3位'年龄': age if age else "未提供",'城市': city if city else "未提供"}print("✅ 用户注册成功!")print("用户信息:")for key, value in user_info.items():print(f" {key}: {value}")return user_info
# 使用关键字参数的多种调用方式
print("=== 方式1: 全部使用位置参数 ===")
register_user("张三", "zhang@example.com", "password123", 25, "北京")
print("\n=== 方式2: 混合使用位置和关键字参数 ===")
register_user("李四", "li@example.com", "secret456", city="上海", age=30)
print("\n=== 方式3: 全部使用关键字参数 ===")
register_user(username="王五", email="wang@example.com", password="pwd789", city="广州"
)
4.3 关键字参数的优势
1. 提高代码可读性
# 难以理解的位置参数
create_window(800, 600, "My App", True, False, True)
# 清晰明了的关键字参数
create_window(width=800,height=600,title="My App",resizable=True,fullscreen=False,vsync=True
)
2. 灵活的参数顺序
def connect_to_database(host, port, username, password, database):"""连接到数据库"""print(f"连接到 {username}@{host}:{port}/{database}")
# 不同的调用顺序,相同的结果
connect_to_database("localhost", 5432, "admin", "123456", "mydb")
connect_to_database(database="mydb",username="admin", password="123456",host="localhost",port=5432
)
关键字参数让我们的代码更加清晰和易于维护。当我们有多个参数时,使用关键字参数可以避免混淆,让代码的意图更加明确。
五、可变参数——处理不确定数量的参数
5.1 什么是可变参数?
可变参数允许函数接受任意数量的参数,这在处理不确定输入数量时非常有用。
两种类型的可变参数:
-
*args
- 接收任意数量的位置参数 -
**kwargs
- 接收任意数量的关键字参数
5.2 *args 的详细示例
示例1:计算任意数量数字的和
def calculate_sum(*numbers):"""计算任意数量数字的和参数:*numbers: 任意数量的数字参数返回:所有数字的和"""print(f"接收到的数字: {numbers}")print(f"参数类型: {type(numbers)}") # 元组total = 0for number in numbers:total += numberreturn total
# 测试各种情况
print(f"两个数字的和: {calculate_sum(10, 20)}")
print(f"三个数字的和: {calculate_sum(1, 2, 3)}")
print(f"五个数字的和: {calculate_sum(1, 2, 3, 4, 5)}")
print(f"没有参数: {calculate_sum()}") # 输出: 0
示例2:创建学生成绩报告
def create_grade_report(student_name, *scores):"""创建学生成绩报告参数:student_name: 学生姓名*scores: 任意数量的成绩"""print(f"\n🎓 学生成绩报告: {student_name}")print("=" * 30)# 处理成绩if scores:print("📊 成绩详情:")for i, score in enumerate(scores, 1):print(f" 科目{i}: {score}分")average = sum(scores) / len(scores)print(f" 平均分: {average:.1f}分")else:print("📊 暂无成绩信息")print("=" * 30)
# 测试各种情况
create_grade_report("张三", 85, 92, 78, 88)
create_grade_report("李四", 95, 96, 98, 97, 99)
create_grade_report("王五") # 没有成绩
5.3 **kwargs 的详细示例
示例1:创建灵活的用户配置
def create_user_profile(username, email, **user_settings):"""创建用户配置文件参数:username: 用户名email: 邮箱**user_settings: 任意数量的用户设置"""profile = {'basic_info': {'username': username,'email': email},'settings': user_settings # 收集所有额外的关键字参数}print(f"\n👤 用户配置文件: {username}")print("-" * 30)print("基本信息:")for key, value in profile['basic_info'].items():print(f" {key}: {value}")if profile['settings']:print("\n个性化设置:")for key, value in profile['settings'].items():print(f" {key}: {value}")else:print("\n暂无个性化设置")return profile
# 测试各种配置
user1 = create_user_profile("alice", "alice@example.com")
user2 = create_user_profile("bob", "bob@example.com", theme="dark", language="en", notifications=False)
user3 = create_user_profile("charlie", "charlie@example.com",theme="light", font_size=16, auto_save=True)
可变参数是Python中非常强大的特性,它们让我们的函数能够处理各种不确定的情况。*args
用于处理不确定数量的位置参数,**kwargs
用于处理不确定数量的关键字参数。
六、递归函数——函数调用自己
6.1 什么是递归函数?
递归函数是指在函数体内调用自身的函数。这是一种强大的编程技巧,特别适合解决可以分解为相似子问题的问题。
递归的基本思想:
-
把大问题分解为小问题
-
小问题的解决方法与大问题相同
-
存在一个或多个基本情况(终止条件)
6.2 递归函数的经典示例
示例1:计算阶乘
def factorial(n):"""计算n的阶乘 (n!)阶乘定义:n! = n × (n-1) × (n-2) × ... × 10! = 1参数:n: 非负整数返回:n的阶乘"""# 基本情况if n == 0 or n == 1:print(f"factorial({n}) = 1 (基本情况)")return 1# 递归情况print(f"计算 factorial({n}) = {n} × factorial({n-1})")result = n * factorial(n - 1)print(f"factorial({n}) = {result}")return result
# 测试阶乘函数
print("🚀 计算 5 的阶乘:")
result = factorial(5)
print(f"\n最终结果: 5! = {result}")
示例2:斐波那契数列
def fibonacci(n):"""计算斐波那契数列的第n项斐波那契数列定义:F(0) = 0F(1) = 1 F(n) = F(n-1) + F(n-2) (n >= 2)参数:n: 项数返回:斐波那契数列的第n项"""# 基本情况if n == 0:return 0elif n == 1:return 1# 递归情况return fibonacci(n-1) + fibonacci(n-2)
# 测试斐波那契数列
print("🐇 计算斐波那契数列:")
for i in range(10):print(f"F({i}) = {fibonacci(i)}")
6.3 递归的注意事项
1. 必须有终止条件
# 错误的递归:没有终止条件
def infinite_recursion():print("这是一个无限递归!")infinite_recursion() # 这会一直调用自己,直到栈溢出
# 正确的递归:有终止条件
def countdown(n):"""倒计时函数"""if n <= 0: # 终止条件print("发射!🚀")returnprint(f"{n}...")countdown(n - 1) # 递归调用
countdown(5)
2. 递归深度限制
Python有递归深度限制,通常为1000层。如果递归太深,会导致栈溢出错误。
递归是一种强大的编程技术,但需要谨慎使用。确保有明确的终止条件,并且递归深度在合理范围内。
七、实战演示——综合应用案例
7.1 实战项目一:智能计算器系统
让我们创建一个功能丰富的智能计算器,展示各种参数类型的应用:
# 智能计算器系统
def display_calculator_header():"""显示计算器标题"""print("🧮" * 40)print(" 智能计算器系统")print("🧮" * 40)
def show_calculator_menu():"""显示计算器菜单"""print("\n请选择计算类型:")print("1. 基础运算")print("2. 科学计算") print("3. 统计计算")print("4. 退出系统")print("-" * 30)
def basic_operations():"""基础四则运算"""print("\n🔢 基础运算")print("支持的操作: +, -, *, /")try:num1 = float(input("请输入第一个数字: "))operator = input("请输入运算符: ")num2 = float(input("请输入第二个数字: "))if operator == "+":result = num1 + num2elif operator == "-":result = num1 - num2elif operator == "*":result = num1 * num2elif operator == "/":if num2 == 0:print("❌ 错误:除数不能为0!")returnresult = num1 / num2else:print("❌ 不支持的运算符!")returnprint(f"计算结果: {num1} {operator} {num2} = {result}")except ValueError:print("❌ 请输入有效的数字!")
def scientific_calculations():"""科学计算"""print("\n🔬 科学计算")print("1. 幂运算")print("2. 平方根")print("3. 绝对值")choice = input("请选择科学计算类型 (1-3): ")try:if choice == "1":base = float(input("请输入底数: "))exponent = float(input("请输入指数: "))result = base ** exponentprint(f"{base}^{exponent} = {result}")elif choice == "2":number = float(input("请输入数字: "))if number < 0:print("❌ 负数没有实数平方根!")returnresult = number ** 0.5print(f"√{number} = {result}")elif choice == "3":number = float(input("请输入数字: "))result = abs(number)print(f"|{number}| = {result}")else:print("❌ 无效的选择!")except ValueError:print("❌ 请输入有效的数字!")
def statistical_calculations(*numbers):"""统计计算参数:*numbers: 任意数量的数字"""if not numbers:print("📊 请输入要计算的数字(用空格分隔):")try:numbers_input = input().split()numbers = [float(num) for num in numbers_input]except ValueError:print("❌ 输入包含无效数字!")returnif not numbers:print("❌ 没有有效的数字可计算!")returnprint(f"\n📊 数据集: {numbers}")# 基础统计print(f" 数据个数: {len(numbers)}")print(f" 总和: {sum(numbers)}")print(f" 平均值: {sum(numbers)/len(numbers):.2f}")print(f" 最大值: {max(numbers)}")print(f" 最小值: {min(numbers)}")
def run_calculator_system():"""计算器系统主函数"""display_calculator_header()while True:show_calculator_menu()choice = input("请输入您的选择 (1-4): ").strip()if choice == "1":basic_operations()elif choice == "2":scientific_calculations()elif choice == "3":statistical_calculations() # 让用户输入数字elif choice == "4":print("\n感谢使用智能计算器系统!")print("再见!🧮")breakelse:print("❌ 无效的选择,请重新输入!")
# 启动计算器系统
if __name__ == "__main__":run_calculator_system()
7.2 实战项目二:递归目录树生成器
# 递归目录树生成器(模拟)
def generate_directory_tree(depth=0, max_depth=3, current_path=""):"""模拟生成目录结构(递归)参数:depth: 当前深度max_depth: 最大深度current_path: 当前路径"""# 基本情况:达到最大深度if depth >= max_depth:returnindent = " " * depthlevel_label = "📁" if depth == 0 else "📄"# 模拟一些文件和文件夹items = []if depth == 0:items = ["src", "docs", "tests", "README.md"]elif depth == 1:if "src" in current_path:items = ["main.py", "utils.py", "config"]elif "docs" in current_path:items = ["tutorial.md", "api.md"]elif "tests" in current_path:items = ["test_main.py", "test_utils.py"]elif depth == 2:if "config" in current_path:items = ["settings.py", "database.py"]# 显示当前层级for item in items:is_dir = "." not in item # 简单判断:没有扩展名的是文件夹icon = "📁" if is_dir else "📄"print(f"{indent}{icon} {item}")# 如果是文件夹,递归显示子内容if is_dir:new_path = f"{current_path}/{item}" if current_path else itemgenerate_directory_tree(depth + 1, max_depth, new_path)
# 显示目录结构
print("📂 项目目录结构:")
generate_directory_tree()
八、每日一题:学生成绩管理系统
题目要求
创建一个学生成绩管理系统,要求实现以下功能:
系统功能需求
-
学生信息管理
-
添加学生信息(学号、姓名、年龄、班级)
-
显示所有学生信息
-
根据学号查找学生
-
-
成绩管理功能
-
为学生添加科目成绩
-
计算每个学生的平均分
-
显示成绩排名
-
-
统计功能
-
统计班级平均分
-
显示优秀学生(平均分≥90)
-
显示需要改进的学生(平均分<60)
-
技术要求
必须使用函数实现以下功能:
-
display_system_header()
- 显示系统标题 -
show_main_menu()
- 显示主菜单 -
add_student(students)
- 添加学生 -
show_all_students(students)
- 显示所有学生 -
find_student(students)
- 查找学生 -
add_grade(students)
- 添加成绩 -
calculate_average(grades)
- 计算平均分 -
show_ranking(students)
- 显示排名 -
show_statistics(students)
- 显示统计信息 -
main()
- 主函数
数据结构建议
# 每个学生用字典表示
student = {'id': '2024001','name': '张三','age': 18,'class': '三年级一班','grades': {'数学': 85,'语文': 92,'英语': 78}
}
# 所有学生存储在列表中
students = [student1, student2, student3, ...]
示例交互
🎓 ================================ 🎓学生成绩管理系统
🎓 ================================ 🎓
请选择操作:
1. 添加学生
2. 显示所有学生
3. 查找学生
4. 添加成绩
5. 显示排名
6. 统计信息
7. 退出系统
请输入您的选择 (1-7):
评分标准
基础要求(必须完成):
-
所有功能都使用函数实现
-
能够添加和显示学生信息
-
能够添加和显示成绩
-
实现基本的统计功能
进阶要求(加分项):
-
使用多种参数类型(位置参数、默认参数、关键字参数)
-
添加数据验证
-
实现成绩修改功能
-
使用递归实现某个功能
提示
-
先设计好数据结构
-
从简单的功能开始实现
-
注意错误处理
-
使用有意义的函数名和变量名
-
测试每个功能是否正常工作
示例数据(用于测试)
# 可以预先添加一些学生数据用于测试
sample_students = [{'id': '2024001','name': '张三','age': 18,'class': '三年级一班','grades': {'数学': 85, '语文': 92, '英语': 78}},{'id': '2024002', 'name': '李四','age': 17,'class': '三年级一班','grades': {'数学': 95, '语文': 88, '英语': 91}}
]
请根据上述要求,使用今天学习的函数参数和递归知识完成这个学生成绩管理系统的开发。注意代码的结构和可读性,确保每个函数都有明确的职责!
九、结语
今天的内容真是丰富啊!我们从基础的函数参数开始,一路学到了递归函数,还通过实战项目巩固了所学知识。🚀
今天的学习要点总结:
-
位置参数 - 最基本的参数类型,按顺序传递
-
默认参数 - 为参数提供默认值,让函数更智能
-
关键字参数 - 通过参数名传递值,提高代码可读性
-
可变参数 - 处理不确定数量的参数(*args和**kwargs)
-
递归函数 - 函数调用自己,解决可分解的问题
学习编程就像搭积木,每个知识点都是一个小积木。今天我们又收集了很多漂亮的积木,接下来就可以搭建更复杂的程序了!
如果你在练习中遇到问题,或者有什么不明白的地方,欢迎来我的博客留言。我会尽力帮助大家解决问题,我们一起进步!
记住:多练习、多思考、多总结是学习编程的最好方法。不要害怕犯错,每个错误都是成长的机会。
下次见啦,继续加油!💪