1. 函数进阶的核心价值
在Python编程中,函数就像乐高积木的基础模块。当你掌握了def、return这些基础语法后,进阶技巧能让你的代码从"能跑"变成"跑得漂亮"。今天我们就来拆解那些让函数真正发挥威力的高阶用法。
重要提示:本文假设读者已经掌握Python函数的基础定义和调用方法。如果还在纠结def和return的关系,建议先夯实基础再来看这些进阶内容。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 函数参数的高级玩法
2.1 默认参数的陷阱与妙用
给参数设置默认值看似简单,但这里有个经典坑:
python复制def add_item(item, items=[]):
items.append(item)
return items
第一次调用add_item('a')返回['a'],第二次调用add_item('b')却返回['a', 'b']。这是因为默认参数在函数定义时就被创建,而不是每次调用时新建。正确的做法是:
python复制def add_item(item, items=None):
items = items or []
items.append(item)
return items
2.2 *args和**kwargs的灵活运用
当参数数量不确定时,这两个特殊参数就派上用场了:
python复制def logger(func):
def wrapper(*args, **kwargs):
print(f"调用{func.__name__},参数:{args}, {kwargs}")
return func(*args, **kwargs)
return wrapper
*args接收任意数量的位置参数,**kwargs接收任意数量的关键字参数。在装饰器和需要高度灵活性的函数中特别有用。
3. 闭包与作用域
3.1 闭包的魔力
闭包是指函数记住了它被定义时的环境。看这个计数器例子:
python复制def counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
每次调用counter()返回的increment函数都有自己的count状态。这在需要保持状态的场景非常有用,比如生成器替代方案。
3.2 global和nonlocal的区别
- global:修改模块级别的变量
- nonlocal:修改嵌套函数中的外层变量
错误使用会导致难以调试的bug。经验法则:尽量少用,优先考虑返回值传递数据。
4. 装饰器的艺术
4.1 基础装饰器实现
装饰器本质上是一个高阶函数:
python复制def timer(func):
import time
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__}执行耗时:{end-start:.4f}秒")
return result
return wrapper
使用时:
python复制@timer
def long_running_func():
# 耗时操作
pass
4.2 带参数的装饰器
需要三层嵌套:
python复制def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def say_hello():
print("Hello!")
5. 函数式编程技巧
5.1 lambda的合理使用
lambda最适合短小的匿名函数场景:
python复制sorted(users, key=lambda x: x['age'])
但复杂的逻辑还是应该用def定义,否则会降低可读性。
5.2 map/filter/reduce的现代替代
虽然这些函数还在,但列表推导式和生成器表达式通常更Pythonic:
python复制# 旧风格
squares = map(lambda x: x**2, range(10))
# 新风格
squares = [x**2 for x in range(10)]
6. 类型提示与文档
6.1 类型注解
Python 3.5+支持类型提示:
python复制def greet(name: str, times: int = 1) -> str:
return " ".join([f"Hello {name}!"] * times)
虽然不影响运行,但能提高代码可读性和IDE支持。
6.2 文档字符串规范
好的docstring应该包含:
python复制def calculate(a, b):
"""计算两个数的特殊运算
Args:
a (int): 第一个操作数
b (int): 第二个操作数
Returns:
int: 计算结果
"""
return (a + b) * (a - b)
7. 函数性能优化
7.1 局部变量加速
访问局部变量比全局变量快得多:
python复制def slow_func():
for i in range(len(global_list)):
# 慢操作
pass
def fast_func():
local_list = global_list
for i in range(len(local_list)):
# 快操作
pass
7.2 lru_cache缓存
对于纯函数(同样输入总是返回同样输出),可以使用缓存:
python复制from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
8. 函数设计原则
8.1 单一职责原则
一个函数应该只做一件事。如果函数名包含"and",很可能违反了这条原则。
8.2 合理控制函数长度
经验值:
- 10行以内:优秀
- 20行以内:可接受
- 超过30行:考虑拆分
9. 调试技巧
9.1 打印函数调用信息
使用inspect模块:
python复制import inspect
def debug(func):
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__}")
print(f"参数:{inspect.signature(func)}")
return func(*args, **kwargs)
return wrapper
9.2 使用pdb调试
在函数中插入断点:
python复制import pdb
def complex_func():
# 某些操作
pdb.set_trace() # 在这里暂停
# 更多操作
10. 实战案例:构建一个简单缓存系统
python复制from functools import wraps
import time
import hashlib
def cache(expire=60):
"""缓存装饰器
Args:
expire (int): 缓存过期时间(秒)
"""
_cache = {}
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
# 生成缓存键
key = hashlib.md5(
f"{func.__name__}{args}{kwargs}".encode()
).hexdigest()
# 检查缓存
if key in _cache:
value, timestamp = _cache[key]
if time.time() - timestamp < expire:
return value
# 执行函数
result = func(*args, **kwargs)
_cache[key] = (result, time.time())
return result
return wrapper
return decorator
@cache(expire=30)
def expensive_operation(x):
time.sleep(2) # 模拟耗时操作
return x * x
这个案例综合运用了装饰器、闭包、缓存等多项进阶技术。在实际项目中,你可以根据需要添加更多功能,比如最大缓存数量限制、缓存淘汰策略等。
