六、函数解析
函数是Python编程的核心概念之一,它允许我们将代码封装为可重用的模块,提高代码的可读性、可维护性和复用性。本文将系统介绍Python函数的定义、参数传递、作用域、装饰器等关键概念,并通过丰富示例展示其实际应用。
文章目录
-
一、函数基础:定义与调用
- 1、基本语法结构
- 2、最简单的函数示例
- 3、带参数的函数
- 4、返回值的使用
-
二、参数传递机制详解
- 1、位置参数与关键字参数
- 2、默认参数
- 3、可变参数 (*args)
- 4、关键字可变参数 (**kwargs)
- 5、参数解包示例
-
三、函数作用域与生命周期
- 1、变量作用域规则
- 2、global关键字
- 3、nonlocal关键字(嵌套函数中使用)
-
四、高阶函数与函数式编程
- 1、函数作为参数传递
- 2、函数作为返回值(闭包)
- 3、lambda表达式(匿名函数)
-
五、函数装饰器:增强函数功能
- 1、基本装饰器示例
- 2、带参数的装饰器
- 3、类装饰器
-
六、函数最佳实践与常见模式
- 1、文档字符串规范
- 2、类型注解 (Python 3.5+)
- 3、函数缓存 (memoization)
- 4、生成器函数(惰性计算)
-
七、综合应用案例:Web请求处理器
-
总结
一、函数基础:定义与调用
1. 基本语法结构
def 函数名(参数列表):
"""函数文档字符串(可选)"""
函数体
return 返回值 # 可选
2. 最简单的函数示例
def greet():
"""一个简单的问候函数"""
print("Hello, Python!")
# 调用函数
greet() # 输出: Hello, Python!
3. 带参数的函数
def greet_person(name):
"""带参数的问候函数"""
print(f"Hello, {name}!")
greet_person("Alice") # 输出: Hello, Alice!
4. 返回值的使用
def add_numbers(a, b):
"""返回两个数的和"""
return a + b
result = add_numbers(3, 5)
print(result) # 输出: 8
二、参数传递机制详解
1、必须参数
调用函数时,Python必须将函数调用中的每个实参都关联到函数定义中的一个形参。为此,最简单的关联方式是基于位置把每个相应位置的实参和形参相关联,调用时的数量必须和声明时的一样。
# 该案例演示了函数位置实参
def func(a, b, c):
print(a, b, c)
func(1, 2, 3) # 1 2 3
# 可以看到,1传给了a,2传给了b,3传给了c
2、关键字参数
函数调用使用关键字参数来确定每个变量传入的参数值,使用关键字参数允许函数调用时参数的顺序与声明时不一致。
# 该案例演示了函数调用时的关键字参数
def printInfo(name,age) :
print("姓名:",name)
print("年龄:",age)
# Python解释器可以通过age和name这样的关键字去和形参进行匹配
printInfo(name = "zhangsan",age = 18)
printInfo(age = 18,name = "zhangsan")
3、默认值参数
定义函数时,可给每个形参指定默认值。在调用函数时,给形参提供了实参则使用指定的实参值,否则使用形参的默认值。因此,给形参指定默认值后,可在函数调用中省略相应的实参。使用默认值可简化函数调用,还可清楚地指出函数的典型用法。注意:非默认参数必须放在默认参数之前
# 该案例演示了函数调用时的默认参数
def printInfo(name, age = 20) :
print("姓名:",name)
print("年龄:",age)
printInfo("zhangsan")
printInfo("lisi",30)
printInfo(age = 40,name = "wangwu")
4、不定长参数
参数的个数是不确定的。
语法:
def 函数名([普通参数,] *var_args_tuple ):
函数体
示例:
# 该案例演示了函数调用时的不定长参数
def printInfo(num,*vartuple):
print(num)
print(vartuple)
printInfo(70,60,50)
注意:
加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
如果形参中出现了不定长参数,那么在调用函数的时候,先通过位置进行必须参数的匹配,然后不定长参数后面的参数必须通过关键字参数匹配
如果不定长的参数后面还有参数,必须通过关键字参数传参
还有一种就是参数带两个星号 **的可变长参数,基本语法如下:
def 函数名([普通参数,] **var_args_dict ):
函数体
加了两个星号 ** 的参数会以字典的形式导入,后面就不能再有其他参数了
# 该案例演示了函数调用时的不定长参数
def printInfo(num,**vardict):
print(num)
print(vardict)
# return
printInfo(10,key1 = 20,key2 = 30)
printInfo(10,a = 20,b = 30)
5、可变参数 (*args)
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">*args</font> 允许函数接受任意数量的位置参数,这些参数会被打包成一个元组
def calculate_average(*numbers):
"""计算任意数量数字的平均值"""
if not numbers:
return 0
return sum(numbers) / len(numbers)
print(calculate_average(1, 2, 3)) # 输出:2.0
print(calculate_average(10, 20, 30, 40)) # 输出:25.0
def wrapper(*args):
print(f"接收到位置参数: {args}")
print(f"类型: {type(args)}") # tuple
print(f"长度: {len(args)}")
# 测试不同调用方式
wrapper(1, 2, 3) # args = (1, 2, 3)
wrapper("a", "b") # args = ('a', 'b')
wrapper() # args = ()
wrapper([1, 2], {3: 4}) # args = ([1, 2], {3: 4})
6、关键字可变参数 (**kwargs)
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">**kwargs</font> 允许函数接受任意数量的关键字参数,这些参数会被打包成一个字典。
def create_profile(**info):
"""创建用户资料字典"""
for key, value in info.items():
print(f"{key}: {value}")
create_profile(name="Charlie", age=28, occupation="Engineer")
# 输出:
# name: Charlie
# age: 28
# occupation: Engineer
def wrapper(**kwargs):
print(f"接收到关键字参数: {kwargs}")
print(f"类型: {type(kwargs)}") # dict
# 测试不同调用方式
wrapper(name="Alice", age=30) # kwargs = {'name': 'Alice', 'age': 30}
wrapper() # kwargs = {}
wrapper(x=1, y=2, z=3) # kwargs = {'x': 1, 'y': 2, 'z': 3}
def wrapper(*args, **kwargs):
print(f"位置参数: {args}")
print(f"关键字参数: {kwargs}")
# 可以接受任何形式的参数
wrapper(1, 2, 3, name="Alice", age=30)
# 输出:
# 位置参数: (1, 2, 3)
# 关键字参数: {'name': 'Alice', 'age': 30}
# *args:接收任意数量的位置参数 → 元组
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
# **kwargs:接收任意数量的关键字参数 → 字典
def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Alice", age=25, city="北京")
# 输出:
# name: Alice
# age: 25
# city: 北京
# 结合使用(顺序:位置参数 > *args > 默认参数 > **kwargs)
def example(a, b, *args, c=10, **kwargs):
print(f"a={a}, b={b}, args={args}, c={c}, kwargs={kwargs}")
example(1, 2, 3, 4, c=20, x=100, y=200)
# a=1, b=2, args=(3, 4), c=20, kwargs={'x': 100, 'y': 200}
7、参数解包示例
def print_coordinates(x, y, z):
print(f"坐标: ({x}, {y}, {z})")
coords = (10, 20, 30)
print_coordinates(*coords) # 等价于 print_coordinates(10, 20, 30)
person = {"name": "David", "age": 35}
def print_person(name, age):
print(f"{name} is {age} years old")
print_person(**person) # 等价于 print_person(name="David", age=35)
8、递归
概念:
递归一种是逻辑思想,将一个大工作分为逐渐减小的小工作,比如说一个和尚要搬50块石头,他想,只要先搬走49块,那剩下的一块就能搬完了,然后考虑那49块,只要先搬走48块,那剩下的一块就能搬完了……,递归是一种思想,只不过在程序中,就是依靠函数嵌套这个特性来实现了
递归案例求一个整数n的阶乘!:
# 该案例演示了求整数的阶乘
5! = 5 * 4 * 3 * 2 *1
# 不使用递归的方式
def get_factorial(num):
res = 1 # 用于存放积
for n in range(1,num+1):
res *= n
return res
print(get_factorial(5))
print("-"*20)
# 递归
def get_factorial2(n):
return n * get_factorial2(n - 1) if n > 1 else 1
print(get_factorial2(5)) # 120
递归执行流程分析
三、函数作用域与生命周期
1. 变量作用域规则
x = 10 # 全局变量
def scope_demo():
y = 20 # 局部变量
print(f"函数内访问全局变量 x: {x}")
# print(z) # 会引发 NameError, z 未定义
scope_demo()
# print(y) # 会引发 NameError, y 是局部变量
2. global 关键字
count = 0
def increment():
global count # 声明使用全局变量
count += 1
increment()
print(count) # 输出: 1
3. nonlocal 关键字(嵌套函数中使用)
def outer():
x = 10
def inner():
nonlocal x # 声明使用外层函数的变量
x += 5
inner()
print(x) # 输出: 15
outer()
四、高阶函数与函数式编程
1. 函数作为参数传递
def apply_operation(x, y, operation):
"""应用传入的运算函数"""
return operation(x, y)
def add(a, b):
return a + b
def multiply(a, b):
return a * b
print(apply_operation(3, 4, add)) # 输出: 7
print(apply_operation(3, 4, multiply)) # 输出: 12
2. 函数作为返回值(闭包)
闭包(Closure)是指在一个外部函数中定义的内部函数,该内部函数引用了外部函数的变量,并且外部函数返回了这个内部函数。即使外部函数已经执行完毕,内部函数仍然可以访问外部函数的变量
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
def outer_function(x):
# 外部函数的局部变量
y = 10
def inner_function(z):
# 内部函数引用了外部函数的变量 x 和 y
return x + y + z
return inner_function
# 创建闭包
closure = outer_function(5) # 5 + 10 + z
print(closure(3)) # 输出: 18 (5 + 10 + 3)
五、函数装饰器:增强函数功能
1. 基本装饰器示例
def my_decorator(func):
"""一个简单的装饰器,打印函数调用信息"""
def wrapper():
print("函数调用前...")
func()
print("函数调用后...")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
等价于
def say_hello():
print("Hello!")
func = my_decorator(say_hello)
say_hello()
# 输出:
# 函数调用前...
# Hello!
# 函数调用后...
2. 带参数的装饰器
def logger(func):
def wrapper(*args, **kwargs):
print(f"调用函数: {func.__name__}")
print(f"参数: {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"返回值: {result}")
return result
return wrapper
@logger
def add(x, y):
return x + y
@logger
def multiply(x, y):
return x * y
add(3, 5)
multiply(4, 6)
3. 类装饰器
类装饰器是指使用类来实现的装饰器,通过 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">__init__</font> 和 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">__call__</font> 方法来实现装饰逻辑。
class TimerDecorator:
"""计算函数执行时间的类装饰器"""
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
import time
start_time = time.time()
result = self.func(*args, **kwargs)
end_time = time.time()
print(f"{self.func.__name__} 执行时间: {end_time - start_time:.4f}秒")
return result
@TimerDecorator
def slow_function(n):
"""模拟耗时操作"""
import time
time.sleep(n)
return "完成"
slow_function(2)
# 输出:
# slow_function 执行时间: 2.0001秒
# 完成
# 最简单的类装饰器
class SimpleDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("函数执行前")
result = self.func(*args, **kwargs)
print("函数执行后")
return result
@SimpleDecorator
def hello():
print("Hello, World!")
hello()
# 输出:
# 函数执行前
# Hello, World!
# 函数执行后
六、函数最佳实践与常见模式
1. 文档字符串规范
def calculate_discount(price, discount_rate, max_discount=0.5):
"""计算折扣后的价格
参数:
price (float): 原始价格
discount_rate (float): 折扣率 (0-1)
max_discount (float): 最大允许折扣率 (默认0.5)
异常:
ValueError: 如果折扣率超出允许范围
"""
if discount_rate > max_discount:
raise ValueError(f"折扣率不能超过{max_discount}")
return price * (1 - discount_rate)
2. 类型注解(Python 3.5+)
from typing import Callable, Any, Optional
def process_item(
item: Any,
transform: Callable[[Any], Any] = lambda x: x,
logger: Optional[Callable[[str], None]] = None
) -> Any:
"""处理项目并返回结果,可选记录日志"""
processed = transform(item)
if logger:
logger(f"Processed: {processed}")
return processed
3. 函数缓存(memoization)
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
"""带缓存的斐波那契数列"""
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(30)) # 快速计算,得益于缓存
4. 生成器函数(惰性计算)
def count_up_to(max_num):
"""生成从1到max_num的数字生成器"""
count = 1
while count <= max_num:
yield count
count += 1
for number in count_up_to(5):
print(number) # 输出:1 2 3 4 5
七、匿名函数
1、语法
Python使用 lambda 来定义匿名函数,所谓匿名,指其不用 def 的标准形式定义函数。
lambda 参数列表: 表达式
lambda 是一个表达式,函数体比def简单很多。
lambda的主体是一个表达式,而不是一个代码块,所以仅仅能在lambda表达式中封装有限的逻辑进去。
lambda函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
2、使用普通函数传参
def operator(a, b):
return a + b
def function(a, b, operator):
return operator(a, b)
print(function(1, 2, ))
3、使用匿名函数传参
def function(a, b, operator):
return operator(a, b)
print(function(1, 2, lambda x, y: x + y))
4、使用匿名函数传参
可以将匿名函数与常用的内置参数搭配使用。
1、 sorted()
有三名学生的姓名和年龄,按年龄排序。
student_list = [{"name": "zhang3", "age": 36}, {"name": "li4", "age": 14}, {"name": "wang5", "age": 27}]
print(sorted(student_list, key=lambda x: x["age"]))
2、 map(),map() 函数对序列中元素逐一处理
map_result = map(lambda x: x * x, [0, 1, 3, 7, 9])
print(list(map_result)) # [0, 1, 9, 49, 81]
3、 filter(),filter() 函数对序列中元素过滤
filter_result = filter(lambda x: x >= 0, [-0, -1, -3, 7, 9])
print(list(filter_result)) # [0, 7, 9]
4、 reduce(),reduce() 函数对序列中元素进行累积
from functools import reduce
reduce_result = reduce(lambda x, y: x * y, [1, 2, 3, 4, 5])
print(reduce_result) # 120
八、综合应用案例:Web请求处理器
from functools import wraps
import time
def handle_errors(func):
"""错误处理装饰器"""
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"请求处理错误: {str(e)}")
return {"error": "Internal server error"}, 500
return wrapper
def validate_input(required_fields):
"""输入验证装饰器工厂"""
def decorator(func):
@wraps(func)
def wrapper(data, *args, **kwargs):
missing = [field for field in required_fields if field not in data]
if missing:
return {"error": f"Missing fields: {', '.join(missing)}"}, 400
return func(data, *args, **kwargs)
return wrapper
return decorator
@handle_errors
@validate_input(["name", "email"])
def process_user_request(data):
"""处理用户请求"""
# 模拟耗时操作
time.sleep(0.1)
# 处理逻辑...
return {
"message": "User created successfully",
"user": {
"name": data["name"],
"email": data["email"]
}
}
# 测试请求处理
test_data = {"name": "Alice", "email": "alice@example.com"}
response = process_user_request(test_data)
print(f"响应内容: {response}")
总结
- 1、函数基础:掌握
def定义、参数传递、返回值等基本概念 - 2、参数处理:理解位置参数、关键字参数、默认参数、可变参数(*args, **kwargs)
- 3、作用域规则:区分全局变量、局部变量,合理使用
global和nonlocal - 4、高阶特性:
- 函数作为一等公民(参数、返回值)
- 闭包与 lambda 表达式
- 装饰器模式(函数增强)
- 5、实用技巧:
- 文档字符串规范
- 类型注解
- 缓存与生成器
- 错误处理装饰器

浙公网安备 33010602011771号