Python 函数进阶:参数、装饰器、匿名函数全精讲
阅读指南:本文专为 Python 初中级工程师打造,从参数底层规则到装饰器高阶实战,再到 lambda 高效场景,全程代码可直接复制运行,覆盖 90% 面试高频考点与工程最佳实践,读完即可独立封装通用装饰器、写出优雅高阶代码。全文约 12000 字,建议收藏 + 关注,持续更新 Python 硬核干货!
前言:为什么函数进阶是 Python 核心分水岭
Python 是一门函数式 + 面向对象双范式语言,函数是一等公民。能否熟练驾驭参数、装饰器、匿名函数,直接决定代码优雅度、复用性与工程能力。
- 初级工程师:只会基础 def、位置参数,代码冗余重复
- 中级工程师:熟练 * args/**kwargs、lambda,简化逻辑
- 高级工程师:自定义装饰器、闭包、高阶函数,实现无侵入增强
本文从基础→进阶→实战→面试四层拆解,保姆级教学,零基础也能吃透。
第一章 函数参数进阶:5 类参数 + 解包 + 避坑全解
1.1 函数参数核心规则与定义
函数参数分为形参(定义时)与实参(调用时),Python 支持 5 种参数类型,调用顺序严格约束:** 位置参数 → 默认参数 → *args → 关键字 - only 参数 → kwargs
1.2 位置参数:最基础也最严格
按定义顺序传递,数量必须完全匹配,缺一不可、多一报错。
python
运行
def add(x, y):
"""位置参数求和"""
return x + y
print(add(10, 20)) # 正常:30
# print(add(10)) # 报错:缺少位置参数y
# print(add(10,20,30))# 报错:参数过多
工程要点:核心必传参数优先使用位置参数,保证调用清晰。
1.3 关键字参数:打破顺序限制
通过参数名指定值,顺序可任意调整,提升代码可读性。
python
运行
def person_info(name, age, city):
return f"姓名:{name},年龄:{age},城市:{city}"
# 关键字参数调用,顺序无关
print(person_info(age=25, city="北京", name="张三"))
适用场景:参数较多时,避免因顺序错误导致 bug。
1.4 默认参数:简化调用,隐藏高频配置
定义时赋值,调用可传可不传,必须放在位置参数之后。
python
运行
def power(base, exp=2):
"""幂运算,默认平方"""
return base ** exp
print(power(3)) # 9(使用默认exp=2)
print(power(3, 3)) # 27(覆盖默认值)
⚠️ 致命坑:可变对象作为默认参数
绝对禁止用列表、字典、集合作为默认参数,会被全局复用,导致数据污染。
python
运行
# 错误写法
def append_item(item, lst=[]):
lst.append(item)
return lst
print(append_item(1)) # [1]
print(append_item(2)) # [1,2](预期[2],实际复用列表)
python
运行
# 正确写法:默认值设为None,内部初始化
def append_item(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
print(append_item(1)) # [1]
print(append_item(2)) # [2]
1.5 可变参数:*args 与 **kwargs,接收任意参数
1.5.1 *args:接收任意位置参数,打包为元组
python
运行
def sum_all(*args):
total = 0
for num in args:
total += num
return total
print(sum_all(1,2,3,4,5)) # 15
print(sum_all(10,20)) # 30
1.5.2 **kwargs:接收任意关键字参数,打包为字典
python
运行
def print_info(**kwargs):
for k, v in kwargs.items():
print(f"{k}: {v}")
print_info(name="李四", age=28, job="工程师")
1.5.3 混合使用:完整参数顺序
python
运行
def func(a, b=2, *args, c, **kwargs):
print(a, b, args, c, kwargs)
func(1, 3, 4, 5, c=6, d=7, e=8)
# 输出:1 3 (4, 5) 6 {'d':7, 'e':8}
1.6 参数解包:与*,一键展开容器
调用函数时,用 * 解包列表 / 元组,** 解包字典,简化传参。
python
运行
# 列表解包
nums = [10, 20]
print(add(*nums)) # 等价add(10,20)
# 字典解包
info = {"name":"王五", "age":30}
print(person_info(**info, city="上海"))
1.7 关键字 - only 参数:强制命名传递
在 * args 后定义参数,必须用关键字传递,避免歧义。
python
运行
def func(a, *args, b, c=0):
print(a, args, b, c)
func(1, 2, 3, b=4) # 正确
# func(1,2,3,4) # 报错:b缺失关键字
1.8 参数进阶总结
- 顺序:位置→默认→*args→关键字 - only→**kwargs
- 默认参数禁用可变对象
- *args 收位置,**kwargs 收关键字
- 解包简化批量传参
- 关键字 - only 参数提升调用安全性
第二章 匿名函数 lambda:一行代码的优雅神器
2.1 什么是 lambda?
lambda 是单行匿名函数,无需 def 定义,无函数名,适用于简单一次性逻辑。语法:lambda 参数1,参数2...: 表达式
- 只能有一行表达式,自动返回结果
- 无 if 多分支、无循环、无赋值语句
- 用完即销毁,不占用命名空间
2.2 基础用法
python
运行
# 定义加法lambda
add_lambda = lambda x, y: x + y
print(add_lambda(5, 6)) # 11
# 平方运算
square = lambda x: x ** 2
print(square(4)) # 16
2.3 核心场景:配合高阶函数
lambda90% 用于 map/filter/sorted/sort 等高阶函数,简化代码。
2.3.1 sorted/sort 自定义排序
python
运行
# 按列表中元组第二个元素升序
lst = [("apple", 5), ("banana", 2), ("orange", 8)]
lst.sort(key=lambda x: x[1])
print(lst) # [('banana',2), ('apple',5), ('orange',8)]
# 按字符串长度降序
str_lst = ["python", "java", "c", "javascript"]
new_lst = sorted(str_lst, key=lambda x: len(x), reverse=True)
2.3.2 map 映射转换
python
运行
# 列表元素乘2
num_lst = [1,2,3,4,5]
res = list(map(lambda x: x*2, num_lst))
print(res) # [2,4,6,8,10]
2.3.3 filter 条件过滤
python
运行
# 筛选偶数
res = list(filter(lambda x: x % 2 == 0, num_lst))
print(res) # [2,4]
2.3.4 max/min 自定义比较
python
运行
# 找字典中年龄最大的人
people = [{"name":"A","age":20}, {"name":"B","age":25}]
max_age = max(people, key=lambda x: x["age"])
2.4 lambda 高级用法
2.4.1 三元表达式结合 lambda
python
运行
compare = lambda x, y: x if x > y else y
print(compare(10, 20)) # 20
2.4.2 闭包中使用 lambda
python
运行
def outer(n):
return lambda x: x * n
double = outer(2)
print(double(5)) # 10
2.5 lambda 使用禁忌
- 禁止复杂逻辑:超过一行请用 def 函数
- 禁止嵌套多层 lambda,可读性极差
- 禁止在全局作用域大量定义 lambda
- 禁止赋值复杂表达式,违背简洁初衷
2.6 lambda vs 普通函数
表格
| 特性 | lambda | 普通函数 def |
|---|---|---|
| 命名 | 匿名 | 有明确函数名 |
| 行数 | 仅限一行 | 任意行数 |
| 逻辑 | 简单表达式 | 复杂逻辑、分支、循环 |
| 复用 | 一次性使用 | 多次复用 |
| 调试 | 难以调试 | 支持文档字符串、断点 |
第三章 装饰器:Python 最优雅的语法糖,无侵入增强函数
3.1 装饰器核心认知
装饰器 =闭包 + 高阶函数 +@语法糖,在不修改原函数代码与调用方式的前提下,为函数添加额外功能。典型场景:日志打印、执行计时、权限校验、参数校验、缓存、重试、事务管理。
3.2 前置知识:闭包与函数一等对象
3.2.1 函数一等对象
- 可作为参数传递
- 可作为返回值返回
- 可赋值给变量
- 可存储在容器中
3.2.2 闭包:记住外层作用域变量
嵌套函数引用外层非全局变量,外层函数执行完毕后,变量仍被保留。
python
运行
def counter():
count = 0
def inner():
nonlocal count
count += 1
return count
return inner
c = counter()
print(c()) # 1
print(c()) # 2
3.3 最简装饰器:入门案例
python
运行
def simple_decorator(func):
def wrapper():
print("函数执行前")
func()
print("函数执行后")
return wrapper
@simple_decorator # 等价 say = simple_decorator(say)
def say():
print("Hello Python")
say()
输出:函数执行前Hello Python函数执行后
3.4 通用装饰器:支持任意参数与返回值
使用 * args/**kwargs 适配所有函数,保留原函数返回值。
python
运行
def通用装饰器(func):
def wrapper(*args, **kwargs):
# 前置操作
print(f"调用函数:{func.__name__}")
# 执行原函数
result = func(*args, **kwargs)
# 后置操作
print(f"函数执行完毕,返回值:{result}")
return result
return wrapper
@通用装饰器
def add(a, b):
return a + b
print(add(3, 4))
3.5 保留原函数元信息:functools.wraps
装饰后原函数__name__/__doc__会被 wrapper 覆盖,用 wraps 修复。
python
运行
import functools
def timer(func):
@functools.wraps(func) # 保留原函数信息
def wrapper(*args, **kwargs):
import time
start = time.time()
res = func(*args, **kwargs)
print(f"耗时:{time.time()-start:.4f}s")
return res
return wrapper
@timer
def test():
"""测试函数"""
return "ok"
print(test.__name__) # test(未修复则为wrapper)
print(test.__doc__) # 测试函数
3.6 带参数的装饰器:三层嵌套
外层接收装饰器参数,中间接收函数,内层包装执行。
python
运行
def log_level(level="INFO"):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"[{level}] 执行函数:{func.__name__}")
return func(*args, **kwargs)
return wrapper
return decorator
@log_level(level="ERROR")
def error_func():
print("出错了")
error_func()
3.7 类装饰器:基于__call__实现
通过类实现装饰器,适合状态保存与复杂逻辑。
python
运行
class Retry:
def __init__(self, max_retry=3):
self.max_retry = max_retry
def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for i in range(self.max_retry):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"第{i+1}次重试,异常:{e}")
raise Exception("重试失败")
return wrapper
@Retry(max_retry=2)
def test_err():
raise ValueError("测试异常")
test_err()
3.8 装饰器堆叠:多个装饰器顺序执行
多个 @装饰器,执行顺序从下到上,调用顺序从上到下。
python
运行
@decorator1
@decorator2
def func():
pass
# 等价:decorator1(decorator2(func))
3.9 工程级装饰器实战
3.9.1 计时装饰器(通用)
python
运行
import time, functools
def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
t_start = time.perf_counter()
res = func(*args, **kwargs)
t_cost = time.perf_counter() - t_start
print(f"{func.__name__} 耗时:{t_cost:.6f}s")
return res
return wrapper
3.9.2 参数类型校验装饰器
python
运行
def type_check(*types):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for arg, typ in zip(args, types):
if not isinstance(arg, typ):
raise TypeError(f"参数类型错误,期望{typ}")
return func(*args, **kwargs)
return wrapper
return decorator
@type_check(int, int)
def add(a, b):
return a + b
3.9.3 缓存装饰器(lru_cache 原理)
python
运行
def cache_decorator(func):
cache = {}
@functools.wraps(func)
def wrapper(*args):
if args in cache:
return cache[args]
res = func(*args)
cache[args] = res
return res
return wrapper
@cache_decorator
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2)
3.10 装饰器总结
- 本质:高阶函数 + 闭包,无侵入增强函数
- 通用模板:wrapper+*args/**kwargs + 返回值
- 必须用 functools.wraps 保留元信息
- 带参数装饰器:三层嵌套
- 类装饰器:适合状态管理
- 工程常用:计时、日志、校验、缓存、重试
第四章 综合实战:参数 + lambda + 装饰器联动案例
4.1 数据处理流水线
python
运行
@timer
def data_process(data_list, *filters, **kwargs):
# 过滤:lambda+filter
for f in filters:
data_list = list(filter(f, data_list))
# 映射:lambda+map
mapper = kwargs.get("mapper", lambda x: x)
data_list = list(map(mapper, data_list))
return sum(data_list)
# 调用:筛选>5,乘2,求和
res = data_process([1,3,6,8,10], lambda x: x>5, mapper=lambda x: x*2)
print(res)
4.2 接口请求加固装饰器
python
运行
@log_level("INFO")
@timer
@Retry(max_retry=3)
def request_api(url):
import requests
return requests.get(url).status_code
request_api("https://www.baidu.com")
第五章 高频面试真题(必背)
- Python 参数传递顺序是什么?
- 默认参数为什么不能用列表?如何修复?
- *args 与 **kwargs 区别与使用场景?
- lambda 限制有哪些?适用场景?
- 装饰器原理是什么?functools.wraps 作用?
- 手写计时装饰器、带参数日志装饰器
- 闭包与装饰器关系?
- 装饰器堆叠执行顺序?
- 类装饰器实现原理?
- 如何用装饰器实现函数缓存?
第六章 学习路线与进阶建议
- 先吃透参数规则,避免工程 bug
- lambda 只用于简单场景,复杂逻辑用 def
- 装饰器从通用模板开始,逐步实现业务需求
- 多看开源框架源码:Flask/Django/Requests 大量使用装饰器
- 封装自己的装饰器库,提升开发效率
结语
函数进阶是 Python 从入门到精通的必经之路,参数保证灵活调用,lambda 简化简洁逻辑,装饰器实现优雅增强。本文覆盖所有核心知识点与工程实战,建议反复练习,把代码敲熟。
原创不易,点赞 + 收藏 + 关注,后续将更新《Python 闭包与装饰器源码解析》《高阶函数实战 100 例》,带你彻底吃透 Python 函数式编程!
更多推荐



所有评论(0)