Python函数(def)详解
函数是Python中用于封装可重用代码的基本构建块。通过函数,我们可以将复杂的程序分解为更小、更易于管理的模块,提高代码的可读性、可维护性和复用性。本文将详细介绍Python函数的定义、参数、返回值、作用域、闭包、装饰器、递归和生成器函数等核心概念和高级用法。
一、函数概述
1. 什么是函数?
函数是一段封装了特定功能的代码块,它可以接收输入参数,执行特定的操作,并返回结果。函数的核心思想是将代码模块化,实现代码的复用和逻辑的分离。
2. Python函数的特点
Python函数具有以下特点:
- 模块化:将复杂的程序分解为更小的模块
- 封装性:隐藏实现细节,只暴露接口
- 可重用性:可以在多个地方调用同一个函数
- 可维护性:便于修改和扩展功能
- 可读性:提高代码的可读性和可理解性
3. 函数的分类
Python函数可以分为以下几类:
- 内置函数:Python自带的函数,如
print()、len()、range()等 - 自定义函数:用户自己定义的函数,使用
def关键字 - 匿名函数:没有名字的函数,使用
lambda关键字定义 - 递归函数:调用自身的函数
- 生成器函数:使用
yield关键字的函数,返回生成器对象
二、函数定义与调用
1. 函数定义的基本语法
使用def关键字定义函数的基本语法如下:
def 函数名(参数列表):
"""函数文档字符串"""
函数体
return 返回值
其中:
def:定义函数的关键字函数名:函数的名称,应符合Python命名规则参数列表:函数的输入参数,可选文档字符串:函数的说明文档,可选函数体:函数的具体实现return:返回函数的结果,可选
2. 函数定义示例
# 无参数、无返回值的函数
def hello():
"""打印问候信息"""
print("Hello, World!")
# 有参数、无返回值的函数
def greet(name):
"""向指定名称的人打招呼"""
print(f"Hello, {name}!")
# 有参数、有返回值的函数
def add(a, b):
"""计算两个数的和并返回结果"""
return a + b
# 有默认参数的函数
def power(base, exponent=2):
"""计算base的exponent次方,默认exponent为2"""
return base ** exponent
# 有可变参数的函数
def sum(*args):
"""计算任意数量参数的和"""
total = 0
for num in args:
total += num
return total
3. 函数调用
定义函数后,可以通过函数名和参数列表来调用函数:
# 调用无参数函数
hello() # 输出:Hello, World!
# 调用有参数函数
greet("张三") # 输出:Hello, 张三!
# 调用有返回值的函数
result = add(3, 5)
print(result) # 输出:8
# 调用有默认参数的函数
print(power(3)) # 输出:9(使用默认参数exponent=2)
print(power(3, 3)) # 输出:27(使用指定参数exponent=3)
# 调用有可变参数的函数
print(sum(1, 2, 3, 4, 5)) # 输出:15
4. 文档字符串
文档字符串(Docstring)是函数的说明文档,用于描述函数的功能、参数和返回值。文档字符串使用三重引号"""定义,可以通过help()函数或.__doc__属性查看:
# 文档字符串示例
def add(a, b):
"""计算两个数的和
参数:
a: 第一个数
b: 第二个数
返回:
两个数的和
"""
return a + b
# 查看文档字符串
help(add) # 通过help()函数查看
print(add.__doc__) # 通过.__doc__属性查看
三、函数参数
Python函数支持多种类型的参数,包括位置参数、关键字参数、默认参数、可变参数等。
1. 位置参数
位置参数是最基本的参数类型,参数的顺序决定了它们的值:
# 位置参数示例
def greet(name, age):
"""向指定名称和年龄的人打招呼"""
print(f"Hello, {name}! You are {age} years old.")
# 调用函数时,参数必须按照定义的顺序传递
greet("张三", 30) # 输出:Hello, 张三! You are 30 years old.
2. 关键字参数
关键字参数允许通过参数名指定参数值,参数的顺序可以任意:
# 关键字参数示例
def greet(name, age):
"""向指定名称和年龄的人打招呼"""
print(f"Hello, {name}! You are {age} years old.")
# 调用函数时,使用参数名指定参数值
greet(age=30, name="张三") # 输出:Hello, 张三! You are 30 years old.
# 混合使用位置参数和关键字参数
greet("张三", age=30) # 输出:Hello, 张三! You are 30 years old.
3. 默认参数
默认参数允许为参数指定默认值,当调用函数时不提供该参数,将使用默认值:
# 默认参数示例
def greet(name, age=18):
"""向指定名称的人打招呼,默认年龄为18"""
print(f"Hello, {name}! You are {age} years old.")
# 不提供默认参数
greet("张三") # 输出:Hello, 张三! You are 18 years old.
# 提供默认参数
greet("张三", 30) # 输出:Hello, 张三! You are 30 years old.
4. 可变位置参数(*args)
可变位置参数允许函数接收任意数量的位置参数,参数将被收集到一个元组中:
# 可变位置参数示例
def sum(*args):
"""计算任意数量参数的和"""
total = 0
for num in args:
total += num
return total
# 调用函数时,可以传递任意数量的位置参数
print(sum(1, 2, 3)) # 输出:6
print(sum(1, 2, 3, 4, 5)) # 输出:15
print(sum()) # 输出:0(没有传递参数)
5. 可变关键字参数(**kwargs)
可变关键字参数允许函数接收任意数量的关键字参数,参数将被收集到一个字典中:
# 可变关键字参数示例
def display_info(**kwargs):
"""显示任意数量的关键字参数"""
for key, value in kwargs.items():
print(f"{key}: {value}")
# 调用函数时,可以传递任意数量的关键字参数
display_info(name="张三", age=30, city="北京")
# 输出:
# name: 张三
# age: 30
# city: 北京
# 混合使用位置参数和可变参数
def greet(name, *args, **kwargs):
"""混合使用位置参数、可变位置参数和可变关键字参数"""
print(f"Hello, {name}!")
if args:
print(f"额外的位置参数: {args}")
if kwargs:
print(f"额外的关键字参数: {kwargs}")
greet("张三", 30, 175, city="北京", occupation="工程师")
# 输出:
# Hello, 张三!
# 额外的位置参数: (30, 175)
# 额外的关键字参数: {'city': '北京', 'occupation': '工程师'}
6. 参数的顺序
函数参数的顺序应该是:位置参数 → 默认参数 → 可变位置参数 → 可变关键字参数:
# 参数顺序示例
def func(positional_arg, default_arg=0, *args, **kwargs):
"""参数顺序:位置参数 → 默认参数 → 可变位置参数 → 可变关键字参数"""
pass
7. 解包参数
可以使用*和**操作符解包序列或字典,将其作为参数传递给函数:
# 解包参数示例
# 解包列表作为位置参数
def add(a, b, c):
return a + b + c
numbers = [1, 2, 3]
print(add(*numbers)) # 输出:6(相当于add(1, 2, 3))
# 解包字典作为关键字参数
def display_info(name, age):
print(f"Name: {name}, Age: {age}")
person = {"name": "张三", "age": 30}
display_info(**person) # 输出:Name: 张三, Age: 30(相当于display_info(name="张三", age=30))
# 混合解包
numbers = [1, 2]
extra = {"c": 3, "d": 4}
def func(a, b, c, d):
return a + b + c + d
print(func(*numbers, **extra)) # 输出:10(相当于func(1, 2, c=3, d=4))
四、函数返回值
1. 返回单个值
函数可以使用return语句返回单个值:
# 返回单个值示例
def square(x):
"""计算x的平方并返回结果"""
return x ** 2
result = square(5)
print(result) # 输出:25
2. 返回多个值
函数可以使用return语句返回多个值,这些值将被打包成一个元组:
# 返回多个值示例
def get_coordinates():
"""返回坐标信息"""
x = 10
y = 20
z = 30
return x, y, z # 返回一个元组
# 接收返回的多个值
x, y, z = get_coordinates()
print(x, y, z) # 输出:10 20 30
# 接收返回的元组
coordinates = get_coordinates()
print(coordinates) # 输出:(10, 20, 30)
print(type(coordinates)) # 输出:<class 'tuple'>
3. 返回None
如果函数没有显式的return语句,或者return语句后面没有值,函数将返回None:
# 返回None示例
def greet(name):
"""打印问候信息"""
print(f"Hello, {name}!")
result = greet("张三")
print(result) # 输出:None
print(type(result)) # 输出:<class 'NoneType'>
# 显式返回None
def do_nothing():
"""什么都不做,显式返回None"""
return None
result = do_nothing()
print(result) # 输出:None
4. 提前返回
函数可以使用return语句提前返回,函数将在执行到return语句时立即结束:
# 提前返回示例
def is_even(num):
"""判断一个数是否为偶数"""
if num % 2 == 0:
return True # 提前返回
return False
print(is_even(4)) # 输出:True
print(is_even(5)) # 输出:False
五、函数的作用域
1. 作用域概述
作用域是变量可见的范围,Python中的变量作用域分为:
- 局部作用域(Local):在函数内部定义的变量,只在函数内部可见
- 嵌套作用域(Enclosing):在嵌套函数外的函数中定义的变量,在嵌套函数内部可见
- 全局作用域(Global):在模块级别定义的变量,在整个模块中可见
- 内置作用域(Built-in):Python内置的变量和函数,如
print()、len()等
2. 局部作用域
在函数内部定义的变量具有局部作用域,只在函数内部可见:
# 局部作用域示例
def my_function():
"""在函数内部定义局部变量"""
local_var = "局部变量"
print(f"函数内部: {local_var}")
my_function() # 输出:函数内部: 局部变量
# 尝试在函数外部访问局部变量
print(f"函数外部: {local_var}") # 抛出NameError异常
3. 全局作用域
在模块级别定义的变量具有全局作用域,在整个模块中可见:
# 全局作用域示例
# 定义全局变量
global_var = "全局变量"
def my_function():
"""在函数内部访问全局变量"""
print(f"函数内部访问全局变量: {global_var}")
my_function() # 输出:函数内部访问全局变量: 全局变量
print(f"函数外部访问全局变量: {global_var}") # 输出:函数外部访问全局变量: 全局变量
4. global关键字
在函数内部修改全局变量时,需要使用global关键字声明变量为全局变量:
# global关键字示例
global_var = "全局变量"
def my_function():
"""在函数内部修改全局变量"""
global global_var # 声明为全局变量
global_var = "修改后的全局变量"
print(f"函数内部修改后的全局变量: {global_var}")
my_function() # 输出:函数内部修改后的全局变量: 修改后的全局变量
print(f"函数外部访问修改后的全局变量: {global_var}") # 输出:函数外部访问修改后的全局变量: 修改后的全局变量
5. nonlocal关键字
在嵌套函数内部修改外部函数的变量时,需要使用nonlocal关键字声明变量为非局部变量:
# nonlocal关键字示例
def outer_function():
"""外部函数"""
outer_var = "外部函数变量"
def inner_function():
"""嵌套函数"""
nonlocal outer_var # 声明为非局部变量
outer_var = "修改后的外部函数变量"
print(f"嵌套函数内部: {outer_var}")
print(f"外部函数调用前: {outer_var}")
inner_function()
print(f"外部函数调用后: {outer_var}")
outer_function()
# 输出:
# 外部函数调用前: 外部函数变量
# 嵌套函数内部: 修改后的外部函数变量
# 外部函数调用后: 修改后的外部函数变量
六、Lambda函数
1. Lambda函数概述
Lambda函数是一种匿名函数,使用lambda关键字定义,通常用于定义简单的函数。Lambda函数的语法如下:
lambda 参数列表: 表达式
2. Lambda函数示例
# Lambda函数示例
# 定义一个简单的lambda函数
square = lambda x: x ** 2
print(square(5)) # 输出:25
# 带有多个参数的lambda函数
add = lambda x, y: x + y
print(add(3, 5)) # 输出:8
# 带有默认参数的lambda函数
power = lambda base, exponent=2: base ** exponent
print(power(3)) # 输出:9
print(power(3, 3)) # 输出:27
# 在高阶函数中使用lambda函数
numbers = [1, 2, 3, 4, 5]
# 使用map()函数和lambda函数
平方数 = list(map(lambda x: x ** 2, numbers))
print(平方数) # 输出:[1, 4, 9, 16, 25]
# 使用filter()函数和lambda函数
偶数 = list(filter(lambda x: x % 2 == 0, numbers))
print(偶数) # 输出:[2, 4]
# 使用sorted()函数和lambda函数
students = [
{"name": "张三", "age": 25},
{"name": "李四", "age": 20},
{"name": "王五", "age": 30}
]
# 按年龄排序
sorted_students = sorted(students, key=lambda x: x["age"])
print(sorted_students)
# 输出:[{'name': '李四', 'age': 20}, {'name': '张三', 'age': 25}, {'name': '王五', 'age': 30}]
3. Lambda函数与普通函数的比较
Lambda函数与普通函数的主要区别是:
- Lambda函数是匿名的,没有函数名
- Lambda函数只能包含一个表达式
- Lambda函数通常用于定义简单的函数
# Lambda函数与普通函数的比较示例
# 普通函数
def square(x):
return x ** 2
# Lambda函数
square = lambda x: x ** 2
# 普通函数
def is_even(x):
return x % 2 == 0
# Lambda函数
is_even = lambda x: x % 2 == 0
七、装饰器
1. 装饰器概述
装饰器(Decorator)是一种特殊的函数,它可以修改其他函数的行为,而不需要修改函数本身的代码。装饰器的核心思想是函数嵌套和闭包。
2. 装饰器的基本原理
装饰器的基本原理是:
- 定义一个装饰器函数,它接收一个函数作为参数
- 在装饰器函数内部定义一个嵌套函数,用于包装原函数
- 在嵌套函数内部调用原函数,并可以添加额外的功能
- 返回嵌套函数
3. 装饰器示例
# 装饰器示例
def my_decorator(func):
"""一个简单的装饰器"""
def wrapper(*args, **kwargs):
"""包装函数"""
print("装饰器开始执行")
result = func(*args, **kwargs)
print("装饰器结束执行")
return result
return wrapper
# 使用装饰器
@my_decorator
def greet(name):
"""打印问候信息"""
print(f"Hello, {name}!")
return f"Greeted {name}"
# 调用装饰后的函数
result = greet("张三")
print(f"函数返回值: {result}")
# 输出:
# 装饰器开始执行
# Hello, 张三!
# 装饰器结束执行
# 函数返回值: Greeted 张三
4. 带参数的装饰器
装饰器可以接受参数,需要在装饰器函数外部再包装一层函数:
# 带参数的装饰器示例
def repeat(times):
"""带参数的装饰器,重复执行函数指定次数"""
def decorator(func):
"""装饰器函数"""
def wrapper(*args, **kwargs):
"""包装函数"""
results = []
for _ in range(times):
results.append(func(*args, **kwargs))
return results
return wrapper
return decorator
# 使用带参数的装饰器
@repeat(3)
def greet(name):
"""打印问候信息"""
print(f"Hello, {name}!")
return f"Greeted {name}"
# 调用装饰后的函数
result = greet("张三")
print(f"函数返回值: {result}")
# 输出:
# Hello, 张三!
# Hello, 张三!
# Hello, 张三!
# 函数返回值: ['Greeted 张三', 'Greeted 张三', 'Greeted 张三']
5. 多个装饰器的使用
可以同时使用多个装饰器,装饰器的执行顺序是从下到上:
# 多个装饰器的使用示例
def decorator1(func):
"""装饰器1"""
def wrapper(*args, **kwargs):
print("装饰器1开始执行")
result = func(*args, **kwargs)
print("装饰器1结束执行")
return result
return wrapper
def decorator2(func):
"""装饰器2"""
def wrapper(*args, **kwargs):
print("装饰器2开始执行")
result = func(*args, **kwargs)
print("装饰器2结束执行")
return result
return wrapper
# 使用多个装饰器,执行顺序是从下到上
@decorator1
@decorator2
def greet(name):
"""打印问候信息"""
print(f"Hello, {name}!")
return f"Greeted {name}"
# 调用装饰后的函数
result = greet("张三")
print(f"函数返回值: {result}")
# 输出:
# 装饰器1开始执行
# 装饰器2开始执行
# Hello, 张三!
# 装饰器2结束执行
# 装饰器1结束执行
# 函数返回值: Greeted 张三
八、递归函数
1. 递归函数概述
递归函数是指在函数内部调用自身的函数。递归函数的核心思想是将复杂的问题分解为更小的、相同结构的子问题。
2. 递归函数的基本原理
递归函数的基本原理是:
- 基本情况(Base Case):递归的终止条件,当满足基本情况时,函数返回一个值,不再递归调用
- 递归情况(Recursive Case):递归的核心部分,将问题分解为更小的子问题,并递归调用自身
3. 递归函数示例
# 递归函数示例
# 计算阶乘
def factorial(n):
"""使用递归计算n的阶乘"""
# 基本情况
if n == 0:
return 1
# 递归情况
return n * factorial(n - 1)
print(factorial(5)) # 输出:120(5! = 5 × 4 × 3 × 2 × 1 = 120)
# 计算斐波那契数列
def fibonacci(n):
"""使用递归计算斐波那契数列的第n项"""
# 基本情况
if n <= 1:
return n
# 递归情况
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(10)) # 输出:55(斐波那契数列:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55)
# 递归遍历目录
def list_files(path):
"""使用递归遍历目录下的所有文件"""
import os
for item in os.listdir(path):
item_path = os.path.join(path, item)
if os.path.isfile(item_path):
print(f"文件: {item_path}")
else:
print(f"目录: {item_path}")
list_files(item_path) # 递归调用
# 调用递归函数
# list_files(".") # 遍历当前目录
4. 递归的优缺点
优点:
- 代码简洁,易于理解
- 适合解决具有递归结构的问题,如树的遍历、图的搜索等
缺点:
- 效率较低,可能存在重复计算
- 占用较多的内存,可能导致栈溢出
5. 递归的优化
可以使用**记忆化(Memoization)**技术优化递归函数,避免重复计算:
# 递归优化(记忆化)示例
# 使用装饰器实现记忆化
def memoize(func):
"""记忆化装饰器"""
cache = {}
def wrapper(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrapper
# 使用记忆化优化斐波那契数列
def fibonacci(n):
"""使用递归计算斐波那契数列的第n项"""
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
# 使用装饰器优化后的斐波那契数列
@memoize
def fibonacci_memoized(n):
"""使用记忆化递归计算斐波那契数列的第n项"""
if n <= 1:
return n
return fibonacci_memoized(n - 1) + fibonacci_memoized(n - 2)
# 测试性能
import time
n = 35
start_time = time.time()
fibonacci(n)
end_time = time.time()
print(f"未优化的斐波那契数列(n={n})耗时: {end_time - start_time:.4f}秒")
start_time = time.time()
fibonacci_memoized(n)
end_time = time.time()
print(f"优化后的斐波那契数列(n={n})耗时: {end_time - start_time:.4f}秒")
九、生成器函数
1. 生成器函数概述
生成器函数是一种特殊的函数,它使用yield关键字代替return关键字返回值。生成器函数返回一个生成器对象,可以使用next()函数或for循环遍历生成器对象。
2. 生成器函数的基本原理
生成器函数的基本原理是:
- 调用生成器函数时,它返回一个生成器对象,而不是执行函数体
- 使用
next()函数或for循环遍历生成器对象时,函数体开始执行 - 当遇到
yield关键字时,函数返回yield后面的值,并暂停执行 - 再次调用
next()函数时,函数体从上次暂停的位置继续执行
3. 生成器函数示例
# 生成器函数示例
def my_generator():
"""一个简单的生成器函数"""
print("生成器函数开始执行")
yield 1
print("生成器函数继续执行")
yield 2
print("生成器函数继续执行")
yield 3
print("生成器函数执行完毕")
# 调用生成器函数,返回生成器对象
gen = my_generator()
print(gen) # 输出:<generator object my_generator at 0x...>
# 使用next()函数遍历生成器对象
print(next(gen)) # 输出:生成器函数开始执行
# 1
print(next(gen)) # 输出:生成器函数继续执行
# 2
print(next(gen)) # 输出:生成器函数继续执行
# 3
print(next(gen)) # 输出:生成器函数执行完毕
# 抛出StopIteration异常
# 使用for循环遍历生成器对象
gen = my_generator()
for item in gen:
print(item)
# 输出:
# 生成器函数开始执行
# 1
# 生成器函数继续执行
# 2
# 生成器函数继续执行
# 3
# 生成器函数执行完毕
4. 生成器函数的应用场景
生成器函数适用于以下场景:
- 生成大量数据,避免占用过多内存
- 实现懒加载,只在需要时才生成数据
- 处理无限序列
# 生成器函数的应用场景示例
# 生成无限序列
def infinite_integers():
"""生成无限整数序列"""
i = 0
while True:
yield i
i += 1
# 使用无限序列
gen = infinite_integers()
for i in range(10):
print(next(gen), end=" ")
print() # 输出:0 1 2 3 4 5 6 7 8 9
# 生成斐波那契数列
def fibonacci_generator(n):
"""生成斐波那契数列的前n项"""
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
# 使用生成器生成斐波那契数列
for num in fibonacci_generator(10):
print(num, end=" ")
print() # 输出:0 1 1 2 3 5 8 13 21 34
十、函数的属性
函数也是对象,具有以下属性:
1. 内置属性
函数的内置属性包括:
__name__:函数的名称__doc__:函数的文档字符串__module__:函数所在的模块__annotations__:函数的参数和返回值的类型注解__code__:函数的代码对象
2. 自定义属性
可以为函数添加自定义属性:
# 函数属性示例
def my_function():
"""一个简单的函数"""
pass
# 访问函数的内置属性
print(f"函数名称: {my_function.__name__}") # 输出:函数名称: my_function
print(f"函数文档: {my_function.__doc__}") # 输出:函数文档: 一个简单的函数
print(f"函数所在模块: {my_function.__module__}") # 输出:函数所在模块: __main__
# 添加自定义属性
my_function.version = "1.0"
my_function.author = "张三"
# 访问自定义属性
print(f"函数版本: {my_function.version}") # 输出:函数版本: 1.0
print(f"函数作者: {my_function.author}") # 输出:函数作者: 张三
十一、函数的最佳实践
1. 函数命名
函数命名应遵循以下规则:
- 使用小写字母和下划线组合
- 名称应具有描述性,清晰表达函数的功能
- 避免使用单字母名称(除非是常用的数学符号)
- 避免使用Python的关键字和内置函数名
2. 函数长度
函数的长度应适中,通常建议不超过50行代码。如果函数过长,应考虑将其分解为多个更小的函数。
3. 函数参数
函数参数应遵循以下规则:
- 参数数量不宜过多,通常建议不超过7个
- 使用默认参数代替复杂的条件语句
- 使用*args和**kwargs处理可变数量的参数
- 参数顺序应为:位置参数 → 默认参数 → 可变位置参数 → 可变关键字参数
4. 函数文档
应为每个函数编写文档字符串,描述函数的功能、参数和返回值。
5. 函数返回值
函数返回值应遵循以下规则:
- 函数应具有明确的返回值
- 避免在同一个函数中返回不同类型的值
- 使用多个返回值时,应确保返回值的顺序和类型一致
6. 错误处理
函数应包含适当的错误处理机制,如异常处理、参数验证等。
7. 代码复用
应避免重复代码,将重复的代码封装为函数。
8. 测试
应为每个函数编写测试用例,确保函数的正确性。
十二、常见错误
1. 参数传递错误
参数传递错误包括:
- 传递的参数数量与函数定义的参数数量不匹配
- 传递的参数类型与函数期望的参数类型不匹配
- 参数顺序错误
# 参数传递错误示例
def add(a, b):
"""计算两个数的和"""
return a + b
# 错误:参数数量不匹配
add(1) # 抛出TypeError异常
# 错误:参数类型不匹配
add("1", 2) # 抛出TypeError异常(Python 3)
# 错误:参数顺序错误
# 在某些情况下可能不会抛出异常,但结果可能不正确
2. 作用域错误
作用域错误包括:
- 在函数外部访问局部变量
- 在函数内部修改全局变量时,忘记使用global关键字
- 在嵌套函数内部修改外部函数的变量时,忘记使用nonlocal关键字
# 作用域错误示例
# 错误:在函数外部访问局部变量
def my_function():
local_var = "局部变量"
print(local_var) # 抛出NameError异常
# 错误:在函数内部修改全局变量时,忘记使用global关键字
global_var = "全局变量"
def my_function():
global_var = "修改后的全局变量" # 创建了一个新的局部变量
my_function()
print(global_var) # 输出:全局变量(全局变量没有被修改)
3. 递归错误
递归错误包括:
- 缺少基本情况,导致无限递归
- 递归深度过大,导致栈溢出
# 递归错误示例
# 错误:缺少基本情况,导致无限递归
def factorial(n):
"""计算n的阶乘"""
return n * factorial(n - 1) # 缺少基本情况
factorial(5) # 抛出RecursionError异常(递归深度过大)
# 错误:递归深度过大,导致栈溢出
Python的默认递归深度限制约为1000
def deep_recursion(n):
"""深度递归"""
if n == 0:
return 0
return deep_recursion(n - 1) + 1
deep_recursion(1000) # 抛出RecursionError异常(递归深度超过限制)
十三、总结
函数是Python中用于封装可重用代码的基本构建块,通过函数,我们可以将复杂的程序分解为更小、更易于管理的模块。本文介绍了Python函数的以下核心概念和高级用法:
函数定义与调用:
- 函数的基本语法
- 函数的定义和调用
- 文档字符串
函数参数:
- 位置参数、关键字参数、默认参数
- 可变位置参数(*args)、可变关键字参数(**kwargs)
- 参数解包
函数返回值:
- 返回单个值
- 返回多个值
- 返回None
- 提前返回
函数的作用域:
- 局部作用域、嵌套作用域、全局作用域、内置作用域
- global关键字、nonlocal关键字
Lambda函数:
- Lambda函数的语法
- Lambda函数的应用场景
装饰器:
- 装饰器的基本原理
- 装饰器的定义和使用
- 带参数的装饰器
- 多个装饰器的使用
递归函数:
- 递归函数的基本原理
- 递归函数的示例
- 递归的优化
生成器函数:
- 生成器函数的基本原理
- 生成器函数的示例
- 生成器函数的应用场景
函数的属性:
- 函数的内置属性
- 函数的自定义属性
函数的最佳实践:
- 函数命名、长度、参数、文档、返回值
- 错误处理、代码复用、测试
通过掌握Python函数的各种概念和用法,可以编写出更简洁、更高效、更易维护的Python代码。
发布网站:荣殿教程(zhangrongdian.com)
作者:张荣殿