08 函数
1. 引言:为什么使用函数?
在Python编程中,函数是代码复用的核心工具。它们允许你将特定任务封装成一个独立的单元,通过调用函数来执行任务,从而提高代码的可读性、可维护性和效率。
简单来说就是一个功能,如果你要在100个地方用,可以把这部分代码复制100份,显然很容易写出屎山代码;也可以直接使用一个函数进行包装,所以后续如果要用这个功能,只需要一句代码调用函数即可,开发效率大大提高!
函数的核心优势包括:
- 代码复用:避免重复编写相同代码。
- 模块化设计:将大程序分解为小函数,便于协作和维护。
- 易于测试:每个函数可独立测试。
- 提高可读性:函数名能描述任务意图。
本文将详细讲解Python函数的定义、参数传递、返回值、调用机制以及相关高级概念。无论你是初学者还是有经验的开发者,都能从中获益。我们将使用Python代码示例来逐步演示,确保内容实用可靠。
接下来,我们从基础开始,逐步深入。
2. 如何定义函数
在Python中,使用def关键字定义函数。语法如下:
| def function_name(parameters):
# 函数体:执行任务的代码
return value # 可选,返回结果
|
def:声明函数的关键字。
function_name:函数名,遵循变量命名规则(如小写字母和下划线)。
parameters:参数列表,用逗号分隔,表示输入值。
函数体:缩进的代码块,执行具体逻辑。
return:可选语句,用于返回值;若无return,函数返回None。
示例:定义一个简单函数
下面定义一个函数greet,它接受一个名字参数,并返回问候语。
| def greet(name,sex):
if sex == "male":
message = "你好, " + name + "先生"
else:
message = "你好, " + name + "女士"
return message
sex = "male"
name = "张三"
if sex == "male":
print(greet(name,sex)) # 调用greet函数
else:
print(greet(name,sex)) # 调用greet函数
|
从上面的例子我们可以看到,我有两处需要使用到 greet 函数,可能有的人会问,那我直接把 message 的内容写到 print 里面不是更方便吗?为何要多此一举,确实是这样,在这个例子中,我们当然可以这样写:
| sex = "male"
name = "张三"
if sex == "male":
print("你好, " + name + "先生")
else:
print("你好, " + name + "女士")
|
但是在实际场景中,问题往往是更加复杂的,比如在判断性别的同时还要判断国家,不同国家的人采用不同的语言打招呼,甚至更加复杂的需求,你就很难在一个print语句中写完所有的功能,而使用函数不管你的需求有多么复杂,我都可以包裹在函数主体中,需要用的时候直接调用即可。
3. 函数参数详解
参数是函数输入的变量。Python支持多种参数类型,使函数更灵活。
3.1 位置参数
位置参数是最基本类型,根据顺序传递值。调用时,实参顺序必须匹配形参顺序。
| def add(a, b): # a和b是位置参数
return a + b
result = add(3, 5) # 调用:a=3, b=5
print(result) # 输出: 8
|
如果顺序错乱,会导致错误。例如,add(5, 3)会正确工作(此时5传递给 a, 3传递给 b),但add(b=5, a=3)需要关键字参数语法,这就严格定义了对应关系。
3.2 关键字参数
调用时,可以指定参数名,忽略顺序,这可以提高可读性。
| result = add(b=5, a=3) # 关键字参数调用
print(result) # 输出: 8
|
位置参数和关键字参数可混合使用,但位置参数必须在关键字参数前,否则会报错。
3.3 默认参数
定义函数时,可为参数设置默认值。调用时,如果省略该参数,使用默认值。
| def greet(name, greeting="你好"): # greeting有默认值
return f"{greeting}, {name}!"
print(greet("Alice")) # 输出: 你好, Alice!
print(greet("Bob", "Hello")) # 输出: Hello, Bob!
|
默认参数必须在非默认参数后定义。例如,def func(a, b=10):有效,但def func(a=5, b):无效。
3.4 可变参数
Python允许处理不定数量的参数:
*args:收集多余的位置参数为元组。
**kwargs:收集多余的关键字参数为字典。
| # 案例1:*args处理任意位置参数
def sum_all(*args):
total = 0
for num in args:
total += num
return total
print(sum_all(1, 2, 3)) # 输出: 6
# 案例2:**kwargs处理任意关键字参数
def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Alice", age=30)
# 输出:
# name: Alice
# age: 30
# 案例3:结合使用*args和**kwargs,注意*args在**kwargs这个参数之前
def combined_example(*args, **kwargs):
"""
同时使用*args和**kwargs的函数
这使得函数可以接受任意位置参数和任意关键字参数
"""
print("位置参数:", args)
print("关键字参数:", kwargs)
print("\n示例3: 结合使用")
combined_example(1, 2, 3, name="Charlie", age=35)
# 输出:
# 位置参数: (1, 2, 3)
# 关键字参数: {'name': 'Charlie', 'age': 35}
|
可变参数在需要灵活输入时很有用,如处理用户数据。
4. 返回值与return语句
函数使用return语句输出结果。如果无return,函数返回None。return可返回多个值(作为元组)。
示例:返回单个值和多个值
| def square(x):
return x ** 2 # 返回平方值
print(square(4)) # 输出: 16
def min_max(numbers):
return min(numbers), max(numbers) # 返回两个值(元组)
result = min_max([3, 1, 4, 2])
print(result) # 输出: (1, 4)
min_val, max_val = min_max([3, 1, 4, 2]) # 解包元组
print(f"最小值: {min_val}, 最大值: {max_val}") # 输出: 最小值: 1, 最大值: 4
|
返回值可以是任何类型,包括列表、字典或自定义对象。
5. 函数调用机制
函数调用是执行函数代码的过程。基本语法:function_name(arguments)。Python支持嵌套调用和递归。
5.1 基本调用
传递实参给形参,执行函数体,调用时,实参可以是表达式或变量。
| def multiply(a, b):
return a * b # 计算两个数的乘积
product = multiply(4, 5) # 调用函数
print(product) # 输出: 20
|
5.2 嵌套调用
函数可以调用其他函数,形成逻辑链。
| def multiply(a, b):
return a * b # 计算两个数的乘积
def add(a, b):
return a + b # 计算两个数的加和
def multiply_and_add(x, y, z): # 在一个函数体内调用其他的函数
temp = multiply(x, y) # 调用multiply函数
return add(temp, z) # 调用add函数
print(multiply_and_add(2, 3, 4)) # 输出: 10 (因为2*3=6, 6+4=10)
|
5.3 递归调用
函数可以调用自身,用于解决分治问题(如阶乘),需要注意递归需有终止条件,否则无限循环。
| def factorial(n):
if n == 0:
return 1 # 只有当n=0的时候才结束“递”,往回传递,称为“归”
else:
return n * factorial(n - 1) # 递归调用自身
print(factorial(5)) # 输出: 120
|
6. 高级函数概念
6.1 Lambda函数
Lambda是匿名函数,用于简单操作。语法:lambda parameters: expression。
| ## 案例1:简单乘法函数
double = lambda x: x * 2 # 冒号前面的是传递的参数,后面是具体表达式
print(double(5)) # 输出: 10
''' 其实就等同于下面这个函数
def double(x):
return x * 2
'''
## 案例2:在排序中使用
points = [(1, 2), (3, 1), (2, 3)]
# 在下式中,相当于points将每个point交给key,key根据point[1]也就是y坐标进行排序
points.sort(key=lambda point: point[1]) # 按y坐标排序
print(points) # 输出: [(3, 1), (1, 2), (2, 3)]
# 案例3(拓展):对字典列表按值排序
students = [{'name': 'Alice', 'score': 88}, {'name': 'Bob', 'score': 75}, {'name': 'Cathy', 'score': 92}]
students.sort(key=lambda d: d['score'],reverse=True) # 按score升序
print(students) # 输出: [{'name': 'Cathy', 'score': 92}, {'name': 'Alice', 'score': 88}, {'name': 'Bob', 'score': 75}]
|
Lambda适合一次性任务,复杂逻辑建议用def定义。
6.2 作用域:全局与局部变量
函数内部变量是局部的,外部是全局的。使用global关键字访问全局变量。
| count = 0 # 全局变量
def increment():
global count # 声明使用全局变量
count += 1
increment() # 调用一次函数,执行函数内对应的操作
print(count) # 输出: 1
|
避免滥用全局变量,优先使用参数传递。
Python函数是编程基石。希望通过上面的案例,你可以学会如何定义、参数化、调用函数,并探索了高级特性。记住:
- 函数使代码更模块化和可重用。
- 实践是关键:多写函数,处理真实问题。