第5天-函数
哪吒 2023/6/15
# 第5天-Python函数
今天我们来学习Python中最重要的概念之一:函数(Function)。函数是编程的核心,掌握了函数,你就掌握了编程的精髓!
# 函数是什么?
想象一下生活中的场景:
- 🍳 做饭:你给厨师食材(输入),厨师做出美食(输出)
- 🧮 计算器:你输入数字和运算符,计算器给出结果
- 🏭 工厂:输入原材料,输出成品
Python的函数就是这样的"加工厂"!
函数定义:函数是一段可重复使用的代码块,它接收输入(参数),执行特定任务,并可能返回结果。
# 一、函数的基本语法
# 1.1 定义函数的语法
def 函数名(参数1, 参数2, ...):
"""函数说明文档(可选)"""
# 函数体:要执行的代码
return 返回值 # 可选
语法要点:
def
:定义函数的关键字函数名
:遵循变量命名规则参数
:函数的输入,可以有0个或多个:
:不要忘记冒号- 缩进:函数体必须缩进
return
:返回结果(可选)
# 1.2 最简单的函数
# 定义一个最简单的函数
def say_hello():
print("你好,欢迎学习Python!")
# 调用函数
say_hello() # 输出:你好,欢迎学习Python!
小白提示:定义函数只是"制作模板",调用函数才是"使用模板"!
# 1.3 带参数的函数
# 带一个参数的函数
def greet(name):
print(f"你好,{name}!")
# 调用函数时传入参数
greet("小明") # 输出:你好,小明!
greet("Alice") # 输出:你好,Alice!
# 带多个参数的函数
def introduce(name, age, city):
print(f"我叫{name},今年{age}岁,来自{city}")
introduce("张三", 25, "北京")
# 输出:我叫张三,今年25岁,来自北京
# 1.4 带返回值的函数
# 计算两个数的和
def add(a, b):
result = a + b
return result # 返回计算结果
# 使用返回值
sum_result = add(3, 5)
print(f"3 + 5 = {sum_result}") # 输出:3 + 5 = 8
# 可以直接在表达式中使用
print(f"10 + 20 = {add(10, 20)}") # 输出:10 + 20 = 30
重要概念:
- 有
return
的函数会返回值,可以赋值给变量- 没有
return
的函数返回None
return
后面的代码不会执行
# 二、函数参数详解
# 2.1 位置参数(必需参数)
位置参数是最基本的参数类型,调用时必须按顺序传入:
def calculate_rectangle_area(length, width):
"""计算矩形面积"""
area = length * width
return area
# 按位置传参:第一个是length,第二个是width
area1 = calculate_rectangle_area(5, 3) # length=5, width=3
print(f"矩形面积:{area1}") # 输出:矩形面积:15
# 位置不能搞错!
area2 = calculate_rectangle_area(3, 5) # length=3, width=5
print(f"矩形面积:{area2}") # 输出:矩形面积:15(结果相同,但概念不同)
# 2.2 关键字参数
可以通过参数名指定值,不用考虑顺序:
def create_user_profile(name, age, city, job):
return f"姓名:{name},年龄:{age},城市:{city},职业:{job}"
# 使用关键字参数,顺序可以任意
profile1 = create_user_profile(name="张三", age=28, city="上海", job="程序员")
profile2 = create_user_profile(job="设计师", city="深圳", name="李四", age=26)
print(profile1)
print(profile2)
# 位置参数和关键字参数可以混用,但位置参数必须在前面
profile3 = create_user_profile("王五", 30, city="广州", job="老师")
print(profile3)
# 2.3 默认参数
为参数设置默认值,调用时可以不传该参数:
def greet_user(name, greeting="你好", punctuation="!"):
return f"{greeting},{name}{punctuation}"
# 使用默认参数
print(greet_user("小明")) # 输出:你好,小明!
# 覆盖部分默认参数
print(greet_user("小红", "早上好")) # 输出:早上好,小红!
# 覆盖所有默认参数
print(greet_user("小李", "晚安", "。")) # 输出:晚安,小李。
# 使用关键字参数跳过某些默认参数
print(greet_user("小王", punctuation="???")) # 输出:你好,小王???
默认参数注意事项:
- 默认参数必须放在位置参数后面
- 不要使用可变对象(如列表、字典)作为默认参数
# 2.4 可变参数(*args)
当不知道会传入多少个参数时,使用*args
:
def calculate_sum(*numbers):
"""计算任意数量数字的和"""
total = 0
for num in numbers:
total += num
return total
# 传入不同数量的参数
print(calculate_sum(1, 2, 3)) # 输出:6
print(calculate_sum(10, 20, 30, 40)) # 输出:100
print(calculate_sum(5)) # 输出:5
print(calculate_sum()) # 输出:0
# 更简洁的写法
def calculate_sum_v2(*numbers):
return sum(numbers)
print(calculate_sum_v2(1, 2, 3, 4, 5)) # 输出:15
# 2.5 关键字可变参数(**kwargs)
当需要接收任意数量的关键字参数时,使用**kwargs
:
def create_student_info(name, **other_info):
"""创建学生信息"""
info = f"学生姓名:{name}\n"
for key, value in other_info.items():
info += f"{key}:{value}\n"
return info
# 传入不同的关键字参数
student1 = create_student_info(
"张三",
age=20,
major="计算机科学",
grade="大二",
gpa=3.8
)
print(student1)
student2 = create_student_info(
"李四",
age=19,
hobby="篮球",
hometown="北京"
)
print(student2)
# 2.6 参数组合使用
def complex_function(required_arg, default_arg="默认值", *args, **kwargs):
"""演示各种参数类型的组合使用"""
print(f"必需参数:{required_arg}")
print(f"默认参数:{default_arg}")
print(f"可变参数:{args}")
print(f"关键字参数:{kwargs}")
print("-" * 30)
# 各种调用方式
complex_function("必须的")
complex_function("必须的", "修改默认值")
complex_function("必须的", "修改默认值", 1, 2, 3)
complex_function("必须的", "修改默认值", 1, 2, 3, name="张三", age=25)
# 三、函数的返回值
# 3.1 单个返回值
def get_circle_area(radius):
"""计算圆的面积"""
import math
area = math.pi * radius ** 2
return area
area = get_circle_area(5)
print(f"半径为5的圆的面积:{area:.2f}") # 输出:半径为5的圆的面积:78.54
# 3.2 多个返回值
def get_rectangle_info(length, width):
"""计算矩形的面积和周长"""
area = length * width
perimeter = 2 * (length + width)
return area, perimeter # 返回元组
# 接收多个返回值
area, perimeter = get_rectangle_info(5, 3)
print(f"面积:{area},周长:{perimeter}")
# 也可以作为元组接收
result = get_rectangle_info(4, 6)
print(f"结果元组:{result}") # 输出:结果元组:(24, 20)
print(f"面积:{result[0]},周长:{result[1]}")
# 3.3 条件返回
def check_grade(score):
"""根据分数返回等级"""
if score >= 90:
return "优秀"
elif score >= 80:
return "良好"
elif score >= 70:
return "中等"
elif score >= 60:
return "及格"
else:
return "不及格"
# 测试不同分数
scores = [95, 85, 75, 65, 55]
for score in scores:
grade = check_grade(score)
print(f"分数{score}:{grade}")
# 3.4 提前返回
def divide_numbers(a, b):
"""安全的除法运算"""
if b == 0:
print("错误:除数不能为0")
return None # 提前返回,避免错误
result = a / b
return result
# 测试
print(divide_numbers(10, 2)) # 输出:5.0
print(divide_numbers(10, 0)) # 输出:错误:除数不能为0,然后是None
# 四、函数的作用域
# 4.1 局部变量 vs 全局变量
# 全局变量
global_var = "我是全局变量"
counter = 0
def demo_scope():
# 局部变量
local_var = "我是局部变量"
print(f"函数内部访问全局变量:{global_var}")
print(f"函数内部的局部变量:{local_var}")
demo_scope()
print(f"函数外部访问全局变量:{global_var}")
# print(local_var) # 错误!无法在函数外访问局部变量
# 4.2 修改全局变量
counter = 0 # 全局变量
def increment_counter():
global counter # 声明要修改全局变量
counter += 1
print(f"计数器增加到:{counter}")
def show_counter():
print(f"当前计数器值:{counter}")
show_counter() # 输出:当前计数器值:0
increment_counter() # 输出:计数器增加到:1
increment_counter() # 输出:计数器增加到:2
show_counter() # 输出:当前计数器值:2
# 4.3 变量查找顺序(LEGB规则)
x = "全局变量"
def outer_function():
x = "外层函数变量"
def inner_function():
x = "内层函数变量"
print(f"内层函数中的x:{x}")
inner_function()
print(f"外层函数中的x:{x}")
outer_function()
print(f"全局作用域中的x:{x}")
# 输出:
# 内层函数中的x:内层函数变量
# 外层函数中的x:外层函数变量
# 全局作用域中的x:全局变量
LEGB规则:Python按照 Local → Enclosing → Global → Built-in 的顺序查找变量
# 五、Lambda表达式(匿名函数)
# 5.1 什么是Lambda表达式?
Lambda表达式是一种创建简单函数的快捷方式,适合一行就能完成的简单操作。
# 普通函数
def square(x):
return x ** 2
# Lambda表达式(匿名函数)
square_lambda = lambda x: x ** 2
# 两者效果相同
print(square(5)) # 输出:25
print(square_lambda(5)) # 输出:25
# 5.2 Lambda语法
# 基本语法:lambda 参数: 表达式
# 单个参数
double = lambda x: x * 2
print(double(4)) # 输出:8
# 多个参数
add = lambda a, b: a + b
print(add(3, 5)) # 输出:8
# 无参数
get_pi = lambda: 3.14159
print(get_pi()) # 输出:3.14159
# 条件表达式
max_value = lambda a, b: a if a > b else b
print(max_value(10, 20)) # 输出:20
# 5.3 Lambda的实际应用
# 1. 与内置函数配合使用
numbers = [1, 2, 3, 4, 5]
# 使用map():对每个元素应用函数
squares = list(map(lambda x: x**2, numbers))
print(f"平方:{squares}") # 输出:平方:[1, 4, 9, 16, 25]
# 使用filter():过滤元素
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(f"偶数:{even_numbers}") # 输出:偶数:[2, 4]
# 使用sorted():自定义排序
students = [('Alice', 85), ('Bob', 90), ('Charlie', 78)]
sorted_by_score = sorted(students, key=lambda student: student[1])
print(f"按分数排序:{sorted_by_score}")
# 输出:按分数排序:[('Charlie', 78), ('Alice', 85), ('Bob', 90)]
# 5.4 Lambda vs 普通函数
特性 | Lambda表达式 | 普通函数 |
---|---|---|
语法 | 简洁,一行 | 完整,多行 |
命名 | 匿名 | 有名称 |
复杂度 | 只能是表达式 | 可以包含语句 |
调试 | 难以调试 | 容易调试 |
用途 | 简单操作 | 复杂逻辑 |
# 六、高级函数概念
# 6.1 递归函数
递归是函数调用自己的编程技巧,适合解决可以分解为相似子问题的问题。
# 经典例子:计算阶乘
def factorial(n):
"""计算n的阶乘:n! = n × (n-1) × ... × 1"""
# 基础情况(递归终止条件)
if n == 0 or n == 1:
return 1
# 递归情况
else:
return n * factorial(n - 1)
# 测试
for i in range(6):
print(f"{i}! = {factorial(i)}")
# 输出:
# 0! = 1
# 1! = 1
# 2! = 2
# 3! = 6
# 4! = 24
# 5! = 120
# 斐波那契数列
def fibonacci(n):
"""计算斐波那契数列的第n项"""
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
# 打印前10项斐波那契数列
print("斐波那契数列前10项:")
for i in range(10):
print(f"F({i}) = {fibonacci(i)}")
递归注意事项:
- 必须有终止条件(基础情况)
- 递归调用必须向终止条件靠近
- 递归深度不能太大(Python默认限制1000层)
# 6.2 嵌套函数
在函数内部定义另一个函数:
def outer_function(x):
"""外层函数"""
def inner_function(y):
"""内层函数"""
return y * 2
# 在外层函数中调用内层函数
result = inner_function(x) + 10
return result
print(outer_function(5)) # 输出:20 (5*2+10)
# inner_function(5) # 错误!内层函数在外部不可访问
# 6.3 闭包(Closure)
内层函数引用外层函数的变量:
def create_multiplier(factor):
"""创建一个乘法器函数"""
def multiplier(number):
return number * factor # 引用外层函数的参数
return multiplier # 返回内层函数
# 创建不同的乘法器
double = create_multiplier(2)
triple = create_multiplier(3)
print(double(5)) # 输出:10 (5 * 2)
print(triple(5)) # 输出:15 (5 * 3)
# 每个乘法器都"记住"了自己的factor值
print(double(10)) # 输出:20
print(triple(10)) # 输出:30
# 6.4 装饰器基础
装饰器是一种特殊的函数,用来修改或增强其他函数的功能:
def timer_decorator(func):
"""计时装饰器"""
import time
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs) # 调用原函数
end_time = time.time()
print(f"函数 {func.__name__} 执行时间:{end_time - start_time:.4f}秒")
return result
return wrapper
# 使用装饰器
@timer_decorator
def slow_function():
"""一个慢函数"""
import time
time.sleep(1) # 模拟耗时操作
return "任务完成"
# 调用被装饰的函数
result = slow_function()
print(result)
# 输出:
# 函数 slow_function 执行时间:1.0012秒
# 任务完成
# 七、函数式编程基础
# 7.1 高阶函数
高阶函数是接受函数作为参数或返回函数的函数:
def apply_operation(numbers, operation):
"""对数字列表应用指定操作"""
result = []
for num in numbers:
result.append(operation(num))
return result
# 定义一些操作函数
def square(x):
return x ** 2
def cube(x):
return x ** 3
numbers = [1, 2, 3, 4, 5]
# 使用不同的操作
squares = apply_operation(numbers, square)
cubes = apply_operation(numbers, cube)
print(f"原数字:{numbers}")
print(f"平方:{squares}")
print(f"立方:{cubes}")
# 7.2 常用内置高阶函数
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# map():对每个元素应用函数
squares = list(map(lambda x: x**2, numbers))
print(f"平方:{squares}")
# filter():过滤元素
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(f"偶数:{even_numbers}")
# reduce():累积操作
from functools import reduce
sum_all = reduce(lambda x, y: x + y, numbers)
print(f"所有数字的和:{sum_all}")
# any():任意一个为True
has_even = any(x % 2 == 0 for x in numbers)
print(f"是否包含偶数:{has_even}")
# all():所有都为True
all_positive = all(x > 0 for x in numbers)
print(f"是否都是正数:{all_positive}")
# 八、实战练习
# 8.1 练习1:温度转换器
def celsius_to_fahrenheit(celsius):
"""摄氏度转华氏度"""
fahrenheit = (celsius * 9/5) + 32
return fahrenheit
def fahrenheit_to_celsius(fahrenheit):
"""华氏度转摄氏度"""
celsius = (fahrenheit - 32) * 5/9
return celsius
def temperature_converter():
"""温度转换主程序"""
print("温度转换器")
print("1. 摄氏度转华氏度")
print("2. 华氏度转摄氏度")
choice = input("请选择转换类型 (1/2): ")
if choice == '1':
celsius = float(input("请输入摄氏度: "))
fahrenheit = celsius_to_fahrenheit(celsius)
print(f"{celsius}°C = {fahrenheit:.2f}°F")
elif choice == '2':
fahrenheit = float(input("请输入华氏度: "))
celsius = fahrenheit_to_celsius(fahrenheit)
print(f"{fahrenheit}°F = {celsius:.2f}°C")
else:
print("无效选择")
# 运行程序
# temperature_converter()
# 8.2 练习2:学生成绩管理
def calculate_average(scores):
"""计算平均分"""
if not scores:
return 0
return sum(scores) / len(scores)
def get_grade(score):
"""根据分数获取等级"""
if score >= 90:
return 'A'
elif score >= 80:
return 'B'
elif score >= 70:
return 'C'
elif score >= 60:
return 'D'
else:
return 'F'
def analyze_scores(student_scores):
"""分析学生成绩"""
print("学生成绩分析报告")
print("=" * 30)
for name, scores in student_scores.items():
avg_score = calculate_average(scores)
grade = get_grade(avg_score)
print(f"学生:{name}")
print(f" 各科成绩:{scores}")
print(f" 平均分:{avg_score:.2f}")
print(f" 等级:{grade}")
print("-" * 20)
# 测试数据
student_data = {
"张三": [85, 92, 78, 96],
"李四": [76, 88, 82, 79],
"王五": [95, 87, 91, 93]
}
analyze_scores(student_data)
# 8.3 练习3:简单计算器
def add(a, b):
"""加法"""
return a + b
def subtract(a, b):
"""减法"""
return a - b
def multiply(a, b):
"""乘法"""
return a * b
def divide(a, b):
"""除法"""
if b == 0:
return "错误:除数不能为0"
return a / b
def calculator():
"""简单计算器"""
operations = {
'+': add,
'-': subtract,
'*': multiply,
'/': divide
}
print("简单计算器")
print("支持的操作:+, -, *, /")
print("输入 'quit' 退出")
while True:
try:
expression = input("请输入计算表达式 (如: 5 + 3): ")
if expression.lower() == 'quit':
print("再见!")
break
# 解析输入
parts = expression.split()
if len(parts) != 3:
print("格式错误,请使用格式:数字 操作符 数字")
continue
num1, operator, num2 = parts
num1, num2 = float(num1), float(num2)
if operator in operations:
result = operations[operator](num1, num2)
print(f"结果:{num1} {operator} {num2} = {result}")
else:
print("不支持的操作符")
except ValueError:
print("输入错误,请输入有效的数字")
except Exception as e:
print(f"发生错误:{e}")
# 运行计算器
# calculator()
# 九、函数最佳实践
# 9.1 函数设计原则
# ✅ 好的函数设计
def calculate_circle_area(radius):
"""计算圆的面积
Args:
radius (float): 圆的半径
Returns:
float: 圆的面积
Raises:
ValueError: 当半径为负数时
"""
if radius < 0:
raise ValueError("半径不能为负数")
import math
return math.pi * radius ** 2
# ❌ 不好的函数设计
def calc(r):
# 没有文档说明
# 变量名不清晰
# 没有错误处理
return 3.14 * r * r
# 9.2 函数命名规范
# ✅ 好的函数命名
def get_user_age(user_id):
"""获取用户年龄"""
pass
def is_valid_email(email):
"""检查邮箱是否有效"""
pass
def calculate_total_price(items):
"""计算总价格"""
pass
# ❌ 不好的函数命名
def func1(x): # 名称不明确
pass
def getData(): # 不符合Python命名规范
pass
def do_everything(): # 功能不单一
pass
# 9.3 函数长度和复杂度
# ✅ 单一职责,简洁明了
def validate_password(password):
"""验证密码强度"""
if len(password) < 8:
return False, "密码长度至少8位"
if not any(c.isupper() for c in password):
return False, "密码必须包含大写字母"
if not any(c.islower() for c in password):
return False, "密码必须包含小写字母"
if not any(c.isdigit() for c in password):
return False, "密码必须包含数字"
return True, "密码强度合格"
# 测试
passwords = ["123456", "Password", "Password123"]
for pwd in passwords:
is_valid, message = validate_password(pwd)
print(f"密码 '{pwd}': {message}")
# 十、总结
# 10.1 函数知识点总结
概念 | 说明 | 示例 |
---|---|---|
函数定义 | 使用def 关键字 | def func_name(): |
参数类型 | 位置、关键字、默认、可变 | def func(a, b=1, *args, **kwargs): |
返回值 | 使用return 返回结果 | return result |
作用域 | 局部变量vs全局变量 | global variable_name |
Lambda | 匿名函数,简洁语法 | lambda x: x * 2 |
递归 | 函数调用自己 | 阶乘、斐波那契 |
装饰器 | 增强函数功能 | @decorator |
# 10.2 函数使用建议
- 单一职责:每个函数只做一件事
- 命名清晰:函数名要能表达其功能
- 参数合理:参数不要太多(建议不超过5个)
- 文档完整:写好函数说明文档
- 错误处理:考虑异常情况
- 测试充分:编写测试用例
# 10.3 下一步学习方向
掌握了函数后,你可以继续学习:
- 模块和包:代码组织和复用
- 面向对象编程:类和对象
- 异常处理:错误处理机制
- 文件操作:读写文件
- 高级特性:生成器、装饰器等
恭喜你!函数是编程的核心,掌握了函数,你已经具备了编写复杂程序的基础能力。继续加油!🚀
练习建议:
- 尝试重写之前学过的代码,使用函数来组织
- 编写一些实用的小工具函数
- 练习使用不同类型的参数
- 尝试编写递归函数解决问题
- 学会阅读和使用他人编写的函数