python的函数
# 1.概述
函数是Python中最重要的代码组织方式之一,它将一组语句组织在一起,以完成特定任务。函数提供了代码重用、模块化和可维护性的核心机制。
# 2.核心概念
# 2.1.为什么使用函数?
| 优势 | 描述 | 示例 |
|---|---|---|
| 代码重用 | 避免重复编写相同的代码 | 计算面积的函数可以在多处使用 |
| 模块化 | 将复杂问题分解为小问题 | 将数据处理分为读取、处理、输出三个函数 |
| 可维护性 | 更容易调试和修改 | 修改函数内部逻辑,所有调用处自动更新 |
| 可读性 | 使代码更易于理解 | 有意义的函数名让代码自文档化 |
# 2.2.函数的基本结构
def function_name(parameters):
"""文档字符串(可选)"""
# 函数体
return value # 可选
2
3
4
组成部分:
- 函数名:标识函数的名称,遵循变量命名规则
- 参数列表:括号中的变量名,表示调用时可以传递的值
- 函数体:缩进的代码块,包含具体的实现逻辑
- 返回值:通过
return语句将结果返回给调用者
# 3.定义和调用函数
# 3.1.基本函数定义
# 返回平方
def square(x):
return x * x
print(square(4)) # 16
print(square(9)) # 81
# 不带参数和返回值的函数
def say_hello():
print("Hello from function!")
say_hello() # Hello from function!
2
3
4
5
6
7
8
9
10
11
12
# 3.2.函数体缩进规则
Python要求函数体代码必须缩进(通常为4个空格),否则会报错:
def foo():
print("这是函数体") # 正确缩进
# 错误写法:
# def bar():
# print("没有缩进,Python会报错")
2
3
4
5
6
# 3.3.文档字符串
可以在函数内部定义文档字符串(docstring),用于描述函数的作用:
def greet(name):
"""向指定的人打招呼"""
print(f"Hello, {name}!")
# 查看文档字符串
print(greet.__doc__) # 向指定的人打招呼
2
3
4
5
6
# 3.4.带参数的函数
def greet(name):
print(f"Hello, {name}!")
greet("Alice") # Hello, Alice!
greet("Bob") # Hello, Bob!
2
3
4
5
# 3.5.带返回值的函数
def add(a, b):
return a + b
result = add(3, 5)
print(result) # 8
2
3
4
5
# 4.参数类型详解
# 4.1.位置参数(Positional Arguments)
位置参数是最基本的参数类型,调用函数时按照参数的位置一一对应传递。
def add(a, b):
print(f"a={a}, b={b}")
return a + b
result = add(2, 3) # a=2, b=3
print(result) # 5
2
3
4
5
6
特点:
- 参数的顺序很重要,不能颠倒
- 调用时必须提供所有必需参数
- 参数按位置顺序赋值
# 4.2.关键字参数(Keyword Arguments)
关键字参数允许你在调用函数时,通过"参数名=值"的形式传递参数,这样参数顺序就可以任意。
def student_info(name, age, city):
print(f"姓名: {name}, 年龄: {age}, 城市: {city}")
# 使用关键字参数,参数顺序可以不按定义顺序
student_info(age=20, name='Lucy', city='Beijing')
# 输出:姓名: Lucy, 年龄: 20, 城市: Beijing
2
3
4
5
6
优点:
- 不用记住参数顺序
- 增加代码可读性
- 很适合带有默认参数的函数
# 4.3.默认参数(Default Arguments)
默认参数是指在定义函数时为参数提供默认值。在调用函数时,如果对应参数没有传值,则会使用这个默认值。
def greet(name, msg='Hello'):
print(f"{msg}, {name}!")
greet('Alice') # 输出:Hello, Alice!
greet('Bob', msg='Hi') # 输出:Hi, Bob!
2
3
4
5
注意事项:
- 默认参数必须出现在非默认参数之后
- 默认参数常用于大多数情况下使用同一个值的场景
# 错误示例
def foo(a=1, b): # 会报错
pass
# 正确写法
def foo(a, b=1):
pass
2
3
4
5
6
7
# 4.4.可变参数 (*args)
可变参数用于当函数需要接受不定数量的位置参数时,通过在参数前加*来实现。
def show_args(*args):
print(f"参数类型: {type(args)}")
print(f"参数内容: {args}")
show_args(1, 2, 3) # 参数类型: <class 'tuple'>
# 参数内容: (1, 2, 3)
show_args('a', 'b', 'c') # 参数类型: <class 'tuple'>
# 参数内容: ('a', 'b', 'c')
2
3
4
5
6
7
8
特点:
*args不是必须叫args,但习惯上都叫args- 所有传入的位置参数被收集到一个元组中
- 特别适合参数数量不确定时使用
实际应用:
def make_pizza(*toppings):
print("制作一个披萨,添加以下配料:")
for topping in toppings:
print(f"- {topping}")
make_pizza('意大利香肠')
make_pizza('蘑菇', '青椒', '芝士')
2
3
4
5
6
7
# 4.5.关键字可变参数 (**kwargs)
关键字可变参数允许函数接收任意数量的"关键字参数"。这些参数会被自动收集到一个字典中。
def show_kwargs(**kwargs):
print(f"参数类型: {type(kwargs)}")
print(f"参数内容: {kwargs}")
show_kwargs(a=1, b=2, c=3) # 参数类型: <class 'dict'>
# 参数内容: {'a': 1, 'b': 2, 'c': 3}
2
3
4
5
6
特点:
**kwargs不是必须叫kwargs,习惯上都这么命名- 多余的关键字参数汇集到一个字典里
- 常用于不确定会传入哪些命名参数时
综合示例:
def demo(a, *args, b=1, **kwargs):
print(f"a: {a}")
print(f"args: {args}")
print(f"b: {b}")
print(f"kwargs: {kwargs}")
demo(100, 2, 3, x=4, y=5)
# 输出:
# a: 100
# args: (2, 3)
# b: 1
# kwargs: {'x': 4, 'y': 5}
2
3
4
5
6
7
8
9
10
11
12
# 4.6.参数解包
在Python中,*和**不仅可以用于函数定义时接收可变参数,还可以用于参数解包。
# 4.6.1.* 用于解包序列类型
def greet(name, age, city):
print(f"姓名: {name}, 年龄: {age}, 城市: {city}")
# 使用 * 解包列表
person_info = ["Alice", 25, "北京"]
greet(*person_info) # 等同于 greet("Alice", 25, "北京")
# 使用 * 解包元组
data = ("Bob", 30, "上海")
greet(*data) # 等同于 greet("Bob", 30, "上海")
2
3
4
5
6
7
8
9
10
# 4.6.2.** 用于解包字典类型
def create_profile(name, age, city, occupation):
print(f"姓名: {name}, 年龄: {age}, 城市: {city}, 职业: {occupation}")
# 使用 ** 解包字典
profile_data = {
"name": "Charlie",
"age": 28,
"city": "广州",
"occupation": "工程师"
}
create_profile(**profile_data)
2
3
4
5
6
7
8
9
10
11
# 4.6.3.混合使用 * 和 **
def complex_function(a, b, c, d, e):
print(f"a={a}, b={b}, c={c}, d={d}, e={e}")
# 位置参数列表
positional_args = [1, 2]
# 关键字参数字典
keyword_args = {"d": 4, "e": 5}
# 混合解包
complex_function(*positional_args, 3, **keyword_args)
# 等同于 complex_function(1, 2, 3, d=4, e=5)
2
3
4
5
6
7
8
9
10
11
# 5.返回值详解
# 5.1.返回单个值
def get_formatted_name(first_name, last_name):
full_name = f"{first_name}{last_name}"
return full_name
musician = get_formatted_name('张', '三')
print(musician) # 张三
2
3
4
5
6
# 5.2.返回多个值
def operate_numbers(a, b):
sum_result = a + b
diff_result = a - b
product_result = a * b
return sum_result, diff_result, product_result
# 接收元组
result = operate_numbers(10, 5)
print(result) # (15, 5, 50)
# 解包返回值
sum_val, diff_val, product_val = operate_numbers(10, 5)
print(f"Sum: {sum_val}, Difference: {diff_val}, Product: {product_val}")
2
3
4
5
6
7
8
9
10
11
12
13
# 5.3.返回复杂数据结构
def create_student_report(name, **scores):
report = {
'name': name,
'total_score': 0,
'subjects': scores
}
# 计算总分
for score in scores.values():
report['total_score'] += score
# 计算平均分
report['average'] = report['total_score'] / len(scores)
return report
student = create_student_report('Alice', math=95, science=87, english=92)
print(student)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 6.函数文档和注释
# 6.1.文档字符串(Docstring)
文档字符串是紧跟在函数定义后,用三引号包裹的字符串,用于描述函数的用途、参数说明、返回值类型等。
def calculate_circle_area(radius):
"""
计算圆的面积
参数:
radius (float): 圆的半径
返回:
float: 圆的面积
"""
import math
return math.pi * radius ** 2
# 查看文档字符串
print(calculate_circle_area.__doc__)
# 查看函数帮助
help(calculate_circle_area)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 6.2.注释
注释是用#开头的说明性文字,用于解释代码片段的实现思路、注意事项或特殊用途。
def safe_divide(a, b):
"""安全的除法函数"""
# 检查除数是否为零
if b == 0:
return "错误:除数不能为零"
# 执行除法运算
result = a / b
return result
2
3
4
5
6
7
8
9
# 7.变量作用域
# 7.1.作用域类型
Python中的变量作用域有以下几种:
| 作用域类型 | 描述 | 示例 |
|---|---|---|
| 局部作用域 | 变量在函数内部定义,只能在该函数内部使用 | 函数内的局部变量 |
| 全局作用域 | 变量在所有函数体外部定义,可以在整个模块里访问 | 模块级别的变量 |
| 嵌套作用域 | 内部函数可以访问外部函数中的变量 | 闭包中的外部变量 |
| 内置作用域 | Python预先定义的内置标识符 | len, range, print等 |
# 7.2.LEGB原则
Python采用LEGB原则查找变量:
- L: Local(本地作用域)
- E: Enclosing(嵌套函数的外部函数作用域)
- G: Global(全局作用域)
- B: Built-in(内置作用域)
name = "全局变量"
def outer():
name = "外部函数变量"
def inner():
name = "内部函数变量"
print(name) # 输出"内部函数变量"
inner()
print(name) # 输出"外部函数变量"
outer()
print(name) # 输出"全局变量"
2
3
4
5
6
7
8
9
10
11
12
# 7.3.global关键字
global关键字允许我们在函数内部声明某个变量为全局变量,从而可以在函数内部修改它。
counter = 0
def increment():
global counter
counter += 1
increment()
increment()
print(counter) # 2
2
3
4
5
6
7
8
9
注意事项:
- 没有
global关键字时,在函数内对一个变量赋值会将其作为局部变量处理 - 使用
global后,函数内的变量就直接引用外部全局变量
# 7.4.nonlocal关键字
nonlocal关键字用于在嵌套函数中声明变量来自最近的一层非全局作用域(外层函数)。
def outer():
x = "local"
def inner():
nonlocal x # 声明 x 来自外层作用域
x = "nonlocal"
print("inner:", x)
inner()
print("outer:", x)
outer()
# inner: nonlocal
# outer: nonlocal
2
3
4
5
6
7
8
9
10
11
12
13
14
# 8.高级函数特性
# 8.1.函数作为参数
函数不仅可以像变量一样赋值给其他变量,还可以作为参数传递给其他函数。
def apply_operation(numbers, operation):
"""对数字列表应用操作"""
return [operation(x) for x in numbers]
def square(x):
return x ** 2
def double(x):
return x * 2
numbers = [1, 2, 3, 4, 5]
squared = apply_operation(numbers, square)
doubled = apply_operation(numbers, double)
print(squared) # [1, 4, 9, 16, 25]
print(doubled) # [2, 4, 6, 8, 10]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 8.2.嵌套函数
嵌套函数是指在一个函数内部定义另一个函数。内部函数可以访问外部函数的参数和局部变量。
def greet(name):
def format_message():
return f"Hello, {name}!"
return format_message()
print(greet("Alice")) # Hello, Alice!
2
3
4
5
6
用途:
- 实现闭包(closure)
- 将某些逻辑封装到本地作用域
- 作为工厂函数创建带记忆的数据
# 8.3.闭包
闭包是指一个函数可以"记住"它被创建时的环境,即使在其外部函数已经执行完毕后,内部函数依然能够访问其外部作用域的变量。
def make_multiplier(factor):
"""创建乘法器函数"""
def multiplier(x):
return x * factor
return multiplier
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5)) # 10
print(triple(5)) # 15
2
3
4
5
6
7
8
9
10
11
特点:
- 内部函数引用了外部函数的局部变量
- 外部函数返回内部函数
- 内部函数可以访问外部函数的变量,即使外部函数已经执行完毕
# 8.4.装饰器
装饰器本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数。装饰器常用于在不修改原函数代码的情况下,动态地为其添加新功能。
def my_decorator(func):
def wrapper():
print("函数执行前")
func()
print("函数执行后")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
# 输出:
# 函数执行前
# Hello!
# 函数执行后
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
带参数的装饰器:
def logger(func):
def wrapper(*args, **kwargs):
print(f"调用函数 {func.__name__},参数:{args} {kwargs}")
return func(*args, **kwargs)
return wrapper
@logger
def add(x, y, **kwargs):
return x + y
print(add(3, 5, a=1, b=2)) # 8
2
3
4
5
6
7
8
9
10
11
# 9.匿名函数 (Lambda)
匿名函数(lambda表达式)是一种快速定义简单函数的方法,通常用于一些无需命名、只用一次的小函数场景。
# 9.1.基本语法
lambda 参数1, 参数2, ... : 表达式
# 9.2.基本用法
# 基本 lambda 函数
square = lambda x: x ** 2
print(square(5)) # 25
# 在排序中使用
students = [
{'name': 'Alice', 'grade': 85},
{'name': 'Bob', 'grade': 92},
{'name': 'Charlie', 'grade': 78}
]
# 按成绩排序
sorted_students = sorted(students, key=lambda x: x['grade'])
print(sorted_students)
# 在 map 中使用
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
print(squared) # [1, 4, 9, 16, 25]
# 在 filter 中使用
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers) # [2, 4]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
特点:
- 只能包含表达式,不能包含语句
- 自动返回表达式的值
- 适合简单的函数逻辑
# 10.递归函数
递归函数是函数调用自身来解决问题的方法,适合解决可以被分解为规模更小、相似子问题的任务。
# 10.1.基本结构
def func(params):
if 终止条件:
return 结果
else:
# 递归调用自身
return func(更小规模的参数)
2
3
4
5
6
# 10.2.递归示例
def factorial(n):
"""计算阶乘的递归函数"""
if n == 0 or n == 1:
return 1
else:
return n * factorial(n - 1)
print(factorial(5)) # 120
def fibonacci(n):
"""计算斐波那契数列"""
if n <= 1:
return n
else:
return fibonacci(n - 1) + fibonacci(n - 2)
for i in range(10):
print(fibonacci(i), end=" ") # 0 1 1 2 3 5 8 13 21 34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
注意事项:
- 必须设置基线条件(终止条件),避免无限递归
- 递归深度有限制,可能导致栈溢出
- 对于规模较大的问题效率较低
# 11.错误处理
在函数中进行错误处理可以提升程序的健壮性和用户体验。
# 11.1.基本语法
def 函数名(参数):
try:
# 可能抛出异常的操作
except 异常类型1:
# 异常类型1的处理代码
except 异常类型2:
# 异常类型2的处理代码
else:
# 没有发生异常时的代码
finally:
# 无论是否发生异常都执行
2
3
4
5
6
7
8
9
10
11
# 11.2.实际应用
def safe_divide(a, b):
"""安全的除法函数"""
try:
result = a / b
except ZeroDivisionError:
return "错误:除数不能为零"
except TypeError:
return "错误:参数类型不正确"
else:
return result
print(safe_divide(10, 2)) # 5.0
print(safe_divide(10, 0)) # 错误:除数不能为零
print(safe_divide(10, 'a')) # 错误:参数类型不正确
2
3
4
5
6
7
8
9
10
11
12
13
14
# 12.实用函数示例
# 12.1.数据处理函数
def analyze_numbers(numbers):
"""分析数字列表"""
if not numbers:
return None
analysis = {
'count': len(numbers),
'sum': sum(numbers),
'mean': sum(numbers) / len(numbers),
'max': max(numbers),
'min': min(numbers)
}
return analysis
data = [10, 20, 30, 40, 50]
result = analyze_numbers(data)
print(result)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 12.2.文件处理函数
def read_file_safely(filename):
"""安全读取文件内容"""
try:
with open(filename, 'r', encoding='utf-8') as file:
return file.read()
except FileNotFoundError:
return f"错误:文件 {filename} 不存在"
except Exception as e:
return f"读取文件时出错:{str(e)}"
def process_csv_data(file_path, delimiter=','):
"""处理CSV数据"""
import csv
data = []
try:
with open(file_path, 'r', encoding='utf-8') as file:
reader = csv.reader(file, delimiter=delimiter)
for row in reader:
data.append(row)
return data
except Exception as e:
print(f"处理CSV文件时出错:{e}")
return None
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 13.综合示例
# 13.1.学生管理系统
def create_student_management_system():
"""创建学生管理系统"""
students = []
def add_student(name, age, grade):
"""添加学生"""
student = {
'name': name,
'age': age,
'grade': grade
}
students.append(student)
print(f"学生 {name} 添加成功")
def find_student(name):
"""查找学生"""
for student in students:
if student['name'].lower() == name.lower():
return student
return None
def get_student_statistics():
"""获取学生统计信息"""
if not students:
return None
total_students = len(students)
average_grade = sum(s['grade'] for s in students) / total_students
best_student = max(students, key=lambda x: x['grade'])
return {
'total_students': total_students,
'average_grade': round(average_grade, 2),
'best_student': best_student
}
def display_all_students():
"""显示所有学生"""
if not students:
print("没有学生记录")
return
print("\n所有学生信息:")
for i, student in enumerate(students, 1):
print(f"{i}. 姓名: {student['name']}, "
f"年龄: {student['age']}, 成绩: {student['grade']}")
return {
'add_student': add_student,
'find_student': find_student,
'get_statistics': get_student_statistics,
'display_all': display_all_students
}
# 使用示例
sms = create_student_management_system()
sms['add_student']('Alice', 20, 95)
sms['add_student']('Bob', 21, 87)
sms['display_all']()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 14.最佳实践
# 14.1.函数设计原则
- 单一职责:每个函数只做一件事
- 描述性命名:使用有意义的函数名
- 保持简短:函数应该简短且专注
- 使用文档字符串:为函数添加适当的文档
- 避免副作用:函数不应该修改外部状态,除非明确需要
# 14.2.参数设计
- 合理使用默认参数:使函数更灵活
- 参数顺序:位置参数在前,默认参数在后
- 使用*args和kwargs**:提高函数灵活性
- 参数验证:在函数开始处验证参数
# 14.3.错误处理
- 处理异常:在适当的地方处理可能的错误
- 提供有意义的错误信息:帮助用户理解问题
- 使用try-except:优雅地处理异常情况
# 14.4.性能考虑
- 避免不必要的计算:将重复计算提取到函数外部
- 使用生成器:对于大数据集使用生成器函数
- 缓存结果:对于昂贵的计算考虑缓存
# 15.总结
函数是Python编程的核心概念,掌握函数的定义、调用、参数传递、返回值、作用域等概念对于编写高质量的Python代码至关重要。通过合理使用函数,我们可以:
- 提高代码的可重用性和可维护性
- 实现模块化编程
- 简化复杂问题的解决
- 提高代码的可读性和可测试性
掌握函数的高级特性如闭包、装饰器、递归等,能够让我们编写更加灵活和强大的Python程序。