
引言:为什么需要函数?
在前面的课程中,我们编写的代码都是按顺序执行的。但有时候,我们需要重复执行某些操作。
比如:
- 计算多个数的阶乘
- 格式化输出多个学生的信息
- 验证多个用户的密码
如果没有函数,我们需要重复写相同的代码。有了函数,我们可以把代码封装起来,需要时直接调用。
函数是代码复用的基础,掌握了函数,你的代码会更简洁、更易维护。
一、函数的定义和调用
1. 什么是函数
函数是一段具有特定功能的、可重用的代码块。通过函数名,我们可以多次调用这段代码。
python
# 定义函数
def greet():
print("Hello, Python!")
print("欢迎学习函数!")
# 调用函数
greet()
greet()
输出:
Hello, Python!
欢迎学习函数!
Hello, Python!
欢迎学习函数!
2. 函数的基本语法
python
# 基本语法
# def 函数名(参数列表):
# 函数体
# return 返回值
# 示例:计算两个数的和
def add(a, b):
result = a + b
return result
# 调用函数
sum_result = add(3, 5)
print(sum_result) # 输出:8
💡 提示:
def关键字用于定义函数- 函数名要见名知意,使用小写字母和下划线
return用于返回结果,可以省略(省略时返回None)
3. 函数的文档字符串
python
def calculate_area(radius):
"""
计算圆的面积
参数:
radius (float): 圆的半径
返回:
float: 圆的面积
"""
pi = 3.14159
return pi * radius ** 2
# 查看函数文档
print(calculate_area.__doc__)
# 调用函数
area = calculate_area(5)
print(f"半径为5的圆面积是:{area:.2f}")
💡 提示 :文档字符串是函数的说明,使用三引号包裹,可以通过
__doc__属性查看。
4. 函数的返回值
python
# 返回单个值
def square(x):
return x ** 2
result = square(5)
print(result) # 输出:25
# 返回多个值(实际上是返回元组)
def get_min_max(numbers):
return min(numbers), max(numbers)
minimum, maximum = get_min_max([3, 1, 4, 1, 5, 9, 2, 6])
print(f"最小值:{minimum},最大值:{maximum}")
# 没有return语句,返回None
def say_hello():
print("Hello!")
result = say_hello()
print(result) # 输出:None
二、参数和返回值
1. 位置参数
python
def greet(name, message):
print(f"{name},{message}")
# 按位置传递参数
greet("小明", "你好!") # 输出:小明,你好!
greet("你好!", "小明") # 输出:你好!,小明(参数顺序错了)
2. 关键字参数
python
def greet(name, message):
print(f"{name},{message}")
# 使用关键字参数,可以不按顺序
greet(message="你好!", name="小明") # 输出:小明,你好!
3. 默认参数
python
def greet(name, message="你好!"):
print(f"{name},{message}")
# 使用默认参数
greet("小明") # 输出:小明,你好!
greet("小红", "早上好!") # 输出:小红,早上好!
💡 提示:默认参数必须放在非默认参数后面。
python
# ❌ 错误
# def greet(message="你好!", name): # SyntaxError
# pass
# ✅ 正确
def greet(name, message="你好!"):
pass
4. 可变参数
*args:接收任意数量的位置参数
python
def sum_all(*args):
"""计算所有参数的和"""
total = 0
for num in args:
total += num
return total
# 调用
print(sum_all(1, 2, 3)) # 输出:6
print(sum_all(1, 2, 3, 4, 5)) # 输出:15
print(sum_all()) # 输出:0
# args是一个元组
def print_args(*args):
print(f"参数类型:{type(args)}")
print(f"参数内容:{args}")
print_args(1, 2, 3)
输出:
arduino
参数类型:<class 'tuple'>
参数内容:(1, 2, 3)
**kwargs:接收任意数量的关键字参数
python
def print_info(**kwargs):
"""打印所有信息"""
print(f"参数类型:{type(kwargs)}")
for key, value in kwargs.items():
print(f"{key}: {value}")
# 调用
print_info(name="小明", age=20, city="北京")
输出:
vbnet
参数类型:<class 'dict'>
name: 小明
age: 20
city: 北京
混合使用
python
def func(a, b, *args, **kwargs):
print(f"a: {a}")
print(f"b: {b}")
print(f"args: {args}")
print(f"kwargs: {kwargs}")
func(1, 2, 3, 4, 5, name="小明", age=20)
输出:
yaml
a: 1
b: 2
args: (3, 4, 5)
kwargs: {'name': '小明', 'age': 20}
💡 提示:参数顺序必须是:位置参数 → *args → 关键字参数 → **kwargs
5. 参数解包
python
# 列表解包
def add(a, b, c):
return a + b + c
numbers = [1, 2, 3]
result = add(*numbers) # 解包列表
print(result) # 输出:6
# 字典解包
def greet(name, age, city):
print(f"姓名:{name},年龄:{age},城市:{city}")
info = {"name": "小明", "age": 20, "city": "北京"}
greet(**info) # 解包字典
三、变量的作用域
1. 局部变量和全局变量
python
# 全局变量
global_var = "我是全局变量"
def test():
# 局部变量
local_var = "我是局部变量"
print(global_var) # 可以访问全局变量
print(local_var) # 可以访问局部变量
test()
print(global_var) # 可以访问全局变量
# print(local_var) # NameError: name 'local_var' is not defined
💡 提示:
- 全局变量:在函数外部定义,整个程序都可以访问
- 局部变量:在函数内部定义,只能在函数内部访问
2. 修改全局变量
python
count = 0
def increment():
global count # 声明要修改全局变量
count += 1
increment()
increment()
increment()
print(count) # 输出:3
⚠️ 警告 :尽量少用
global,会使代码难以维护。
3. 作用域规则(LEGB规则)
Python查找变量的顺序:
- Local(局部):函数内部
- Enclosing(嵌套):外层函数
- Global(全局):模块级别
- Built-in(内置):Python内置
python
# 示例
x = "全局变量"
def outer():
x = "外层函数变量"
def inner():
x = "内层函数变量"
print(f"inner: {x}") # 输出:内层函数变量
inner()
print(f"outer: {x}") # 输出:外层函数变量
outer()
print(f"global: {x}") # 输出:全局变量
4. nonlocal关键字
python
def outer():
count = 0
def inner():
nonlocal count # 声明要修改外层函数的变量
count += 1
print(f"count: {count}")
inner() # 输出:count: 1
inner() # 输出:count: 2
inner() # 输出:count: 3
print(f"final count: {count}") # 输出:final count: 3
outer()
四、匿名函数和高阶函数
1. lambda匿名函数
lambda函数是一种简洁的匿名函数,用于简单的操作。
python
# 基本语法
# lambda 参数: 表达式
# 普通函数
def square(x):
return x ** 2
# lambda函数
square_lambda = lambda x: x ** 2
print(square(5)) # 输出:25
print(square_lambda(5)) # 输出:25
# 多个参数
add = lambda a, b: a + b
print(add(3, 5)) # 输出:8
# 带默认参数
greet = lambda name, message="你好": f"{name},{message}"
print(greet("小明")) # 输出:小明,你好
2. lambda的应用场景
排序
python
# 按字典的某个键排序
students = [
{"name": "张三", "score": 85},
{"name": "李四", "score": 92},
{"name": "王五", "score": 78}
]
# 使用lambda作为排序依据
sorted_students = sorted(students, key=lambda x: x["score"], reverse=True)
for student in sorted_students:
print(f"{student['name']}: {student['score']}")
输出:
makefile
李四: 92
张三: 85
王五: 78
与map()配合使用
python
# map()函数:对序列中的每个元素应用函数
numbers = [1, 2, 3, 4, 5]
# 使用lambda计算平方
squares = list(map(lambda x: x ** 2, numbers))
print(squares) # 输出:[1, 4, 9, 16, 25]
# 等价于列表推导式
squares = [x ** 2 for x in numbers]
print(squares) # 输出:[1, 4, 9, 16, 25]
与filter()配合使用
python
# filter()函数:过滤序列
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 使用lambda过滤偶数
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # 输出:[2, 4, 6, 8, 10]
# 等价于列表推导式
evens = [x for x in numbers if x % 2 == 0]
print(evens) # 输出:[2, 4, 6, 8, 10]
3. 高阶函数
高阶函数是指接受函数作为参数或返回函数的函数。
map()函数
python
# 对列表中每个元素应用函数
numbers = [1, 2, 3, 4, 5]
# 计算每个数的平方
squares = list(map(lambda x: x ** 2, numbers))
print(squares) # 输出:[1, 4, 9, 16, 25]
# 多个列表
list1 = [1, 2, 3]
list2 = [10, 20, 30]
result = list(map(lambda x, y: x + y, list1, list2))
print(result) # 输出:[11, 22, 33]
filter()函数
python
# 过滤序列
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 过滤出大于5的数
greater_than_5 = list(filter(lambda x: x > 5, numbers))
print(greater_than_5) # 输出:[6, 7, 8, 9, 10]
# 过滤出字符串中的数字
strings = ["1", "2", "a", "3", "b", "4"]
numbers = list(filter(lambda x: x.isdigit(), strings))
print(numbers) # 输出:['1', '2', '3', '4']
reduce()函数
python
from functools import reduce
# 对序列中的元素进行累积操作
numbers = [1, 2, 3, 4, 5]
# 计算乘积
product = reduce(lambda x, y: x * y, numbers)
print(product) # 输出:120 (1*2*3*4*5)
# 计算和
total = reduce(lambda x, y: x + y, numbers)
print(total) # 输出:15 (1+2+3+4+5)
# 带初始值
total = reduce(lambda x, y: x + y, numbers, 10)
print(total) # 输出:25 (10+1+2+3+4+5)
sorted()函数
python
# 自定义排序
students = [
{"name": "张三", "score": 85, "age": 20},
{"name": "李四", "score": 92, "age": 21},
{"name": "王五", "score": 78, "age": 19}
]
# 按成绩排序
by_score = sorted(students, key=lambda x: x["score"], reverse=True)
print("按成绩排序:")
for s in by_score:
print(f"{s['name']}: {s['score']}")
# 按年龄排序
by_age = sorted(students, key=lambda x: x["age"])
print("\n按年龄排序:")
for s in by_age:
print(f"{s['name']}: {s['age']}")
4. 函数作为返回值
python
# 返回函数的函数
def create_multiplier(n):
"""创建一个乘法器"""
return lambda x: x * n
# 创建不同的乘法器
double = create_multiplier(2)
triple = create_multiplier(3)
print(double(5)) # 输出:10
print(triple(5)) # 输出:15
print(double(10)) # 输出:20
五、递归函数
1. 什么是递归
递归是指函数调用自身的过程。递归必须有终止条件,否则会无限循环。
python
# 计算阶乘
def factorial(n):
"""计算n的阶乘"""
# 终止条件
if n == 0 or n == 1:
return 1
# 递归调用
return n * factorial(n - 1)
# 调用
print(factorial(5)) # 输出:120 (5*4*3*2*1)
print(factorial(10)) # 输出:3628800
2. 递归的应用
斐波那契数列
python
def fibonacci(n):
"""计算第n个斐波那契数"""
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
# 打印前10个斐波那契数
for i in range(10):
print(fibonacci(i), end=" ")
# 输出:0 1 1 2 3 5 8 13 21 34
汉诺塔
python
def hanoi(n, source="A", target="C", auxiliary="B"):
"""汉诺塔问题"""
if n == 1:
print(f"移动盘子 1 从 {source} 到 {target}")
return
# 将n-1个盘子从source移动到auxiliary
hanoi(n - 1, source, auxiliary, target)
# 移动第n个盘子
print(f"移动盘子 {n} 从 {source} 到 {target}")
# 将n-1个盘子从auxiliary移动到target
hanoi(n - 1, auxiliary, target, source)
# 3个盘子
hanoi(3)
3. 递归的注意事项
python
# ⚠️ 递归深度限制
import sys
print(f"最大递归深度:{sys.getrecursionlimit()}") # 通常是1000
# 递归过深会报错
# def infinite_recursion():
# infinite_recursion()
# infinite_recursion() # RecursionError: maximum recursion depth exceeded
# 使用缓存优化递归
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci_cached(n):
if n <= 1:
return n
return fibonacci_cached(n - 1) + fibonacci_cached(n - 2)
# 使用缓存后,计算速度大大提升
print(fibonacci_cached(100)) # 可以快速计算
六、实战练习
练习1:计算器函数
python
def calculator(num1, operator, num2):
"""简单计算器"""
if operator == "+":
return num1 + num2
elif operator == "-":
return num1 - num2
elif operator == "*":
return num1 * num2
elif operator == "/":
if num2 == 0:
return "错误:除数不能为0"
return num1 / num2
else:
return "错误:不支持的运算符"
# 测试
print(calculator(10, "+", 5)) # 输出:15
print(calculator(10, "-", 5)) # 输出:5
print(calculator(10, "*", 5)) # 输出:50
print(calculator(10, "/", 5)) # 输出:2.0
print(calculator(10, "/", 0)) # 输出:错误:除数不能为0
练习2:统计函数
python
def analyze_numbers(numbers):
"""分析数字列表,返回统计信息"""
if not numbers:
return None
return {
"count": len(numbers),
"sum": sum(numbers),
"average": sum(numbers) / len(numbers),
"max": max(numbers),
"min": min(numbers)
}
# 测试
data = [10, 20, 30, 40, 50]
stats = analyze_numbers(data)
print(f"数据:{data}")
print(f"数量:{stats['count']}")
print(f"总和:{stats['sum']}")
print(f"平均值:{stats['average']}")
print(f"最大值:{stats['max']}")
print(f"最小值:{stats['min']}")
练习3:装饰器入门
python
import time
def timer_decorator(func):
"""计时装饰器"""
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():
"""模拟耗时操作"""
time.sleep(1)
print("函数执行完成")
# 调用
slow_function()
练习4:函数式编程
python
from functools import reduce
# 数据处理管道
data = [
{"name": "张三", "score": 85, "age": 20},
{"name": "李四", "score": 92, "age": 21},
{"name": "王五", "score": 78, "age": 19},
{"name": "赵六", "score": 95, "age": 22},
{"name": "钱七", "score": 88, "age": 20}
]
# 1. 过滤出成绩大于80的学生
high_scorers = list(filter(lambda x: x["score"] > 80, data))
print("成绩大于80的学生:")
for s in high_scorers:
print(f" {s['name']}: {s['score']}")
# 2. 提取所有成绩
scores = list(map(lambda x: x["score"], data))
print(f"\n所有成绩:{scores}")
# 3. 计算平均分
average = reduce(lambda x, y: x + y, scores) / len(scores)
print(f"平均分:{average:.1f}")
# 4. 按成绩排序
sorted_data = sorted(data, key=lambda x: x["score"], reverse=True)
print("\n按成绩排序:")
for i, s in enumerate(sorted_data, 1):
print(f" {i}. {s['name']}: {s['score']}")
七、常见问题与排错
问题1:忘记return语句
原因 :函数没有返回值 解决方法:添加return语句
python
# ❌ 错误
def add(a, b):
result = a + b
# 忘记return
sum_result = add(3, 5)
print(sum_result) # 输出:None
# ✅ 正确
def add(a, b):
result = a + b
return result
sum_result = add(3, 5)
print(sum_result) # 输出:8
问题2:默认参数是可变对象
原因 :默认参数在函数定义时只创建一次 解决方法:使用None作为默认值
python
# ❌ 错误
def append_to(element, lst=[]):
lst.append(element)
return lst
print(append_to(1)) # 输出:[1]
print(append_to(2)) # 输出:[1, 2](不是[2]!)
# ✅ 正确
def append_to(element, lst=None):
if lst is None:
lst = []
lst.append(element)
return lst
print(append_to(1)) # 输出:[1]
print(append_to(2)) # 输出:[2]
问题3:作用域问题
原因 :在函数内部修改全局变量没有使用global 解决方法:使用global声明
python
count = 0
# ❌ 错误
def increment():
count += 1 # UnboundLocalError
# ✅ 正确
def increment():
global count
count += 1
increment()
print(count) # 输出:1
八、本篇小结
今天,我们完成了以下学习内容:
-
函数的定义和调用:
- 使用
def定义函数 - 函数名要见名知意
- 使用文档字符串说明函数
- 使用
-
参数和返回值:
- 位置参数、关键字参数
- 默认参数、可变参数(*args、**kwargs)
- return返回值
-
变量的作用域:
- 局部变量和全局变量
- LEGB规则
- global和nonlocal关键字
-
匿名函数和高阶函数:
- lambda匿名函数
- map()、filter()、reduce()
- sorted()自定义排序
-
递归函数:
- 递归的概念
- 递归的应用
- 递归深度限制
请记住这三个结论:
- 函数是代码复用的基础:把重复的代码封装成函数
- 参数传递要灵活:合理使用位置参数、关键字参数、默认参数
- 高阶函数很强大:map、filter、reduce可以简化代码
下期预告
在第9期中,我们将学习Python的文件操作,包括:
- 文件的打开和关闭
- 读写文本文件
- 读写CSV和JSON文件
- 文件路径处理
敬请期待!
✍坚持原创,求关注,点赞,收藏