1. Python函数进阶:从基础到高阶的全面解析
作为一名Python开发者,函数是我们每天都要打交道的基本构建块。但很多人停留在基础使用层面,没有充分挖掘Python函数的强大能力。今天我们就来深入探讨Python函数的进阶用法,帮助你在实际项目中写出更优雅、更高效的代码。
Python函数不仅仅是简单的代码封装工具,它支持多种高级特性如闭包、装饰器、生成器等,这些特性让Python在数据处理、Web开发、自动化脚本等领域展现出强大的灵活性。掌握这些进阶技巧,你将能够:
- 编写更简洁、可维护的代码
- 实现更复杂的功能逻辑
- 提升代码的执行效率
- 更好地理解Python生态中的各种框架和库
无论你是Python初学者想要提升技能,还是有一定经验的开发者希望深入理解函数机制,这篇文章都将为你提供实用的知识和技巧。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 函数参数的高级用法
2.1 位置参数与关键字参数
在Python中,函数参数可以分为位置参数和关键字参数。位置参数是按照定义顺序传递的,而关键字参数则是通过参数名明确指定。
python复制def greet(name, message):
print(f"{message}, {name}!")
# 位置参数调用
greet("Alice", "Hello") # 输出: Hello, Alice!
# 关键字参数调用
greet(message="Hi", name="Bob") # 输出: Hi, Bob!
关键字参数的优势在于:
- 提高代码可读性,明确每个参数的含义
- 允许跳过某些参数,只传递需要的参数
- 参数顺序可以任意调整
注意:在函数定义中,位置参数必须放在关键字参数之前。混合使用时,Python会先匹配位置参数,再处理关键字参数。
2.2 默认参数的使用技巧
默认参数可以让函数调用更简洁,但使用时需要注意一些陷阱:
python复制def create_user(name, age, is_active=True, role="member"):
print(f"创建用户: {name}, 年龄: {age}, 状态: {'活跃' if is_active else '非活跃'}, 角色: {role}")
# 只提供必需参数
create_user("张三", 25) # 使用默认的is_active和role
# 覆盖部分默认参数
create_user("李四", 30, role="admin")
# 全部使用关键字参数
create_user(name="王五", age=35, is_active=False, role="guest")
默认参数的常见问题:
- 默认参数在函数定义时就被求值,而不是在调用时
- 可变对象(如列表、字典)作为默认参数可能导致意外行为
python复制# 错误的默认参数用法
def add_item(item, items=[]): # 默认参数在定义时创建,所有调用共享同一个列表
items.append(item)
return items
# 正确的做法
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
2.3 可变参数:*args和**kwargs
Python允许函数接受任意数量的参数,通过*args和**kwargs实现:
python复制def log_message(*args, **kwargs):
print("位置参数:", args)
print("关键字参数:", kwargs)
log_message("错误", "文件未找到", severity="high", timestamp="2023-01-01")
*args收集所有未匹配的位置参数为一个元组,**kwargs收集所有未匹配的关键字参数为一个字典。这种机制在以下场景特别有用:
- 编写装饰器时传递参数
- 实现函数包装器
- 创建灵活的API接口
实际应用示例:计算任意数量数字的平均值
python复制def average(*numbers):
return sum(numbers) / len(numbers) if numbers else 0
print(average(1, 2, 3, 4, 5)) # 输出: 3.0
3. 函数作用域与闭包
3.1 LEGB规则解析
Python中的作用域遵循LEGB规则:
- Local(局部):函数内部定义的变量
- Enclosing(闭包):嵌套函数中外部函数的变量
- Global(全局):模块级别的变量
- Built-in(内置):Python内置的变量名
python复制x = "global" # Global
def outer():
x = "outer" # Enclosing
def inner():
x = "inner" # Local
print(x) # 输出: inner
inner()
print(x) # 输出: outer
outer()
print(x) # 输出: global
理解LEGB规则对于避免变量冲突和正确使用闭包至关重要。
3.2 闭包的实际应用
闭包是指内部函数引用了外部函数的变量,即使外部函数已经执行完毕:
python复制def make_multiplier(factor):
def multiplier(number):
return number * factor
return multiplier
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5)) # 输出: 10
print(triple(5)) # 输出: 15
闭包的典型应用场景:
- 实现装饰器
- 保持状态(替代简单的类)
- 实现回调函数
- 创建函数工厂
提示:在Python 3中,可以使用nonlocal关键字修改闭包中的变量,这在需要维护状态时非常有用。
3.3 global和nonlocal关键字
- global:声明变量为全局变量
- nonlocal:声明变量来自外层函数(但不是全局)
python复制count = 0 # 全局变量
def counter():
global count
count += 1
return count
def outer():
x = 0
def inner():
nonlocal x
x += 1
return x
return inner
print(counter(), counter(), counter()) # 输出: 1 2 3
f = outer()
print(f(), f(), f()) # 输出: 1 2 3
使用这些关键字时要谨慎,过度使用会破坏代码的封装性和可维护性。
4. 装饰器的原理与应用
4.1 装饰器基础语法
装饰器本质上是一个接受函数作为参数并返回新函数的函数:
python复制def simple_decorator(func):
def wrapper():
print("函数执行前")
func()
print("函数执行后")
return wrapper
@simple_decorator
def say_hello():
print("Hello!")
say_hello()
输出:
code复制函数执行前
Hello!
函数执行后
装饰器的@语法糖等同于:
python复制say_hello = simple_decorator(say_hello)
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 greet(name):
print(f"Hello, {name}!")
greet("Alice")
输出:
code复制Hello, Alice!
Hello, Alice!
Hello, Alice!
这种模式在以下场景很有用:
- 重试机制
- 日志记录
- 权限验证
- 性能测试
4.3 类装饰器与内置装饰器
除了函数装饰器,Python还支持类装饰器:
python复制class Timer:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
import time
start = time.time()
result = self.func(*args, **kwargs)
end = time.time()
print(f"{self.func.__name__} 执行时间: {end - start:.4f}秒")
return result
@Timer
def long_running_function():
import time
time.sleep(2)
long_running_function()
Python内置了一些有用的装饰器:
- @staticmethod:定义静态方法
- @classmethod:定义类方法
- @property:定义属性访问器
python复制class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value <= 0:
raise ValueError("半径必须为正数")
self._radius = value
@classmethod
def from_diameter(cls, diameter):
return cls(diameter / 2)
@staticmethod
def pi():
return 3.141592653589793
5. 生成器与yield关键字
5.1 生成器函数基础
生成器函数使用yield关键字返回一个值并暂停执行,下次调用时从暂停处继续:
python复制def countdown(n):
while n > 0:
yield n
n -= 1
for i in countdown(5):
print(i) # 输出: 5 4 3 2 1
生成器的优势:
- 惰性求值,节省内存
- 可以表示无限序列
- 支持管道式数据处理
5.2 生成器表达式
类似于列表推导式,但使用圆括号并返回生成器:
python复制# 列表推导式 - 立即计算所有值
squares_list = [x**2 for x in range(1000000)] # 占用大量内存
# 生成器表达式 - 按需生成值
squares_gen = (x**2 for x in range(1000000)) # 几乎不占内存
print(next(squares_gen)) # 输出: 0
print(next(squares_gen)) # 输出: 1
生成器表达式特别适合处理大数据集,可以避免一次性加载所有数据到内存。
5.3 协程与yield from
Python的生成器还可以作为协程使用,通过send()方法传递数据:
python复制def coroutine():
while True:
received = yield
print(f"收到: {received}")
c = coroutine()
next(c) # 启动生成器
c.send("你好") # 输出: 收到: 你好
c.send("Python") # 输出: 收到: Python
yield from语法可以简化生成器的嵌套:
python复制def chain(*iterables):
for it in iterables:
yield from it
list(chain("ABC", "DEF")) # 输出: ['A', 'B', 'C', 'D', 'E', 'F']
6. 函数式编程工具
6.1 lambda表达式
lambda用于创建匿名函数,适合简单的操作:
python复制# 普通函数定义
def square(x):
return x ** 2
# lambda等效
square = lambda x: x ** 2
# 常用场景:作为参数传递
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, numbers))
lambda的限制:
- 只能包含单个表达式
- 不能包含语句或注解
- 可读性较差,复杂逻辑应使用def
6.2 map、filter和reduce
Python提供了几个内置的高阶函数:
python复制# map: 对可迭代对象应用函数
names = ["alice", "bob", "charlie"]
capitalized = list(map(str.capitalize, names)) # ['Alice', 'Bob', 'Charlie']
# filter: 过滤元素
numbers = [1, 2, 3, 4, 5, 6]
evens = list(filter(lambda x: x % 2 == 0, numbers)) # [2, 4, 6]
# reduce: 累积计算
from functools import reduce
product = reduce(lambda x, y: x * y, [1, 2, 3, 4]) # 24
在现代Python中,列表推导式和生成器表达式通常更受青睐,因为它们通常更易读:
python复制# 使用列表推导式替代map和filter
capitalized = [name.capitalize() for name in names]
evens = [x for x in numbers if x % 2 == 0]
6.3 functools模块实用工具
functools模块提供了一些有用的函数操作工具:
- partial:部分应用函数参数
python复制from functools import partial
def power(base, exponent):
return base ** exponent
square = partial(power, exponent=2)
cube = partial(power, exponent=3)
print(square(5)) # 25
print(cube(5)) # 125
- lru_cache:函数结果缓存
python复制from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 第一次计算会递归调用
print(fibonacci(50)) # 12586269025
# 后续调用直接从缓存读取
print(fibonacci(50)) # 立即返回
- singledispatch:函数重载
python复制from functools import singledispatch
@singledispatch
def process(data):
raise NotImplementedError("未实现的数据类型")
@process.register(str)
def _(data):
return f"处理字符串: {data}"
@process.register(int)
def _(data):
return f"处理整数: {data * 2}"
print(process("hello")) # 处理字符串: hello
print(process(42)) # 处理整数: 84
7. 函数注解与类型提示
7.1 函数注解语法
Python 3引入了函数注解,可以给参数和返回值添加元数据:
python复制def greet(name: str, times: int = 1) -> str:
"""返回重复的问候语"""
return " ".join([f"Hello, {name}!"] * times)
print(greet("Alice", 3))
# 输出: Hello, Alice! Hello, Alice! Hello, Alice!
注解不会影响函数行为,只是提供额外的信息。可以通过__annotations__属性访问:
python复制print(greet.__annotations__)
# 输出: {'name': <class 'str'>, 'times': <class 'int'>, 'return': <class 'str'>}
7.2 类型提示与mypy
结合typing模块,可以实现更丰富的类型提示:
python复制from typing import List, Dict, Optional, Union
def process_data(
items: List[Union[int, str]],
config: Optional[Dict[str, int]] = None
) -> Dict[str, List[str]]:
"""处理数据并返回分类结果"""
config = config or {}
result = {"numbers": [], "strings": []}
for item in items:
if isinstance(item, int):
result["numbers"].append(str(item))
else:
result["strings"].append(item)
return result
可以使用mypy等工具进行静态类型检查:
bash复制pip install mypy
mypy your_script.py
类型提示的好处:
- 提高代码可读性
- 在开发早期发现类型错误
- IDE可以提供更好的代码补全和检查
- 便于大型项目的维护
7.3 可调用对象与协议
Python的typing模块还定义了Callable类型,用于注解函数参数:
python复制from typing import Callable
def apply_operation(
numbers: List[int],
operation: Callable[[int], int]
) -> List[int]:
return [operation(n) for n in numbers]
result = apply_operation([1, 2, 3], lambda x: x * 2)
print(result) # [2, 4, 6]
Python 3.8引入了Protocol,可以定义更灵活的类型约束:
python复制from typing import Protocol
class SupportsClose(Protocol):
def close(self) -> None:
pass
def close_all(resources: List[SupportsClose]) -> None:
for resource in resources:
resource.close()
8. 函数性能优化技巧
8.1 避免不必要的重复计算
对于计算密集型函数,缓存中间结果可以显著提高性能:
python复制def expensive_calculation(x):
# 模拟耗时计算
import time
time.sleep(1)
return x * x
# 简单缓存实现
cache = {}
def cached_calculation(x):
if x not in cache:
cache[x] = expensive_calculation(x)
return cache[x]
# 第一次调用慢
print(cached_calculation(5)) # 约1秒
# 第二次调用快
print(cached_calculation(5)) # 立即返回
对于纯函数(输出只依赖于输入的函数),使用functools.lru_cache更方便:
python复制from functools import lru_cache
@lru_cache(maxsize=None)
def expensive_calculation(x):
import time
time.sleep(1)
return x * x
8.2 局部变量访问更快
Python访问局部变量比全局变量更快,对于频繁使用的全局变量,可以将其转为局部变量:
python复制import math
def calculate(values):
# 将math.sqrt转为局部变量
sqrt = math.sqrt
return [sqrt(x) for x in values]
这种方法在循环中特别有效,可以避免重复的全局变量查找。
8.3 使用内置函数和库
Python的内置函数通常是用C实现的,比纯Python实现快得多:
python复制# 较慢的Python实现
def sum_squares(numbers):
total = 0
for num in numbers:
total += num ** 2
return total
# 更快的实现
def sum_squares(numbers):
return sum(x ** 2 for x in numbers)
对于数值计算,使用NumPy等专用库可以获得更好的性能:
python复制import numpy as np
def numpy_sum_squares(numbers):
arr = np.array(numbers)
return np.sum(arr ** 2)
8.4 避免不必要的函数调用
在循环中创建不必要的函数调用会增加开销:
python复制# 不推荐的写法
def process_data(data):
results = []
for item in data:
results.append(str(item).upper())
return results
# 改进的写法
def process_data(data):
upper = str.upper
return [upper(str(item)) for item in data]
对于简单的转换,列表推导式通常比显式循环更快。
9. 函数调试与测试
9.1 使用装饰器进行调试
可以创建调试装饰器来跟踪函数调用:
python复制def debug(func):
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__},参数: {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"{func.__name__} 返回: {result}")
return result
return wrapper
@debug
def add(a, b):
return a + b
add(3, 5)
输出:
code复制调用 add,参数: (3, 5), {}
add 返回: 8
9.2 单元测试与pytest
为函数编写单元测试是保证质量的重要手段:
python复制# math_operations.py
def divide(a, b):
if b == 0:
raise ValueError("除数不能为零")
return a / b
# test_math_operations.py
import pytest
from math_operations import divide
def test_divide_normal():
assert divide(10, 2) == 5
assert divide(1, 3) == pytest.approx(0.333333, rel=1e-6)
def test_divide_by_zero():
with pytest.raises(ValueError, match="除数不能为零"):
divide(10, 0)
使用pytest运行测试:
bash复制pytest test_math_operations.py -v
9.3 性能分析与优化
使用cProfile模块分析函数性能:
python复制import cProfile
def slow_function():
total = 0
for i in range(100000):
total += i ** 2
return total
cProfile.run('slow_function()')
对于更详细的分析,可以使用line_profiler:
python复制# 安装: pip install line_profiler
# 在函数前添加@profile装饰器
@profile
def slow_function():
total = 0
for i in range(100000):
total += i ** 2
return total
# 运行: kernprof -l -v your_script.py
10. 函数设计最佳实践
10.1 单一职责原则
每个函数应该只做一件事,并且做好:
python复制# 不推荐的写法
def process_user_data(user_data):
# 验证数据
if not user_data.get("name"):
raise ValueError("缺少用户名")
# 格式化数据
formatted = {
"name": user_data["name"].title(),
"age": int(user_data.get("age", 0))
}
# 保存到数据库
db.save(formatted)
# 发送通知
send_email(formatted["name"])
return True
# 推荐的写法
def validate_user_data(data):
if not data.get("name"):
raise ValueError("缺少用户名")
return data
def format_user_data(data):
return {
"name": data["name"].title(),
"age": int(data.get("age", 0))
}
def process_user_data(user_data):
validated = validate_user_data(user_data)
formatted = format_user_data(validated)
db.save(formatted)
send_email(formatted["name"])
return True
10.2 合理的函数长度
一般来说,函数应该足够短小,能够在一屏内完整显示(约20-30行)。如果函数过长,考虑将其拆分为多个小函数。
10.3 有意义的命名
函数名应该清晰表达其功能,使用动词或动词短语:
python复制# 不好的命名
def data(data): ...
def process(): ...
def handle(): ...
# 好的命名
def calculate_average(numbers): ...
def validate_email_address(email): ...
def send_notification(message): ...
10.4 文档字符串与注释
为函数添加清晰的文档字符串(docstring):
python复制def calculate_tax(income, rate=0.15):
"""计算应缴税款
参数:
income (float): 税前收入
rate (float, optional): 税率,默认为0.15
返回:
float: 计算出的税款
异常:
ValueError: 如果收入为负数时抛出
"""
if income < 0:
raise ValueError("收入不能为负数")
return income * rate
使用Google风格或NumPy风格的文档字符串格式,保持一致性。
10.5 错误处理与异常
合理处理异常,避免静默忽略错误:
python复制# 不推荐的写法
def divide(a, b):
try:
return a / b
except:
return None
# 推荐的写法
def divide(a, b):
"""两数相除
参数:
a: 被除数
b: 除数
返回:
除法结果
异常:
ValueError: 当除数为零时抛出
TypeError: 当参数不是数字时抛出
"""
if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
raise TypeError("参数必须是数字")
if b == 0:
raise ValueError("除数不能为零")
return a / b
11. 实际应用案例
11.1 数据管道处理
利用生成器构建高效的数据处理管道:
python复制def read_large_file(file_path):
with open(file_path, "r") as file:
for line in file:
yield line.strip()
def filter_lines(lines, keyword):
for line in lines:
if keyword in line:
yield line
def transform_lines(lines, transform_func):
for line in lines:
yield transform_func(line)
# 构建处理管道
lines = read_large_file("data.log")
filtered = filter_lines(lines, "ERROR")
transformed = transform_lines(filtered, str.upper)
# 按需处理
for line in transformed:
print(line)
这种方法的优势:
- 内存高效,一次只处理一行
- 可组合性强,可以灵活添加处理步骤
- 延迟执行,只有实际使用时才会处理
11.2 缓存装饰器实现
实现一个带过期时间的缓存装饰器:
python复制import time
from functools import wraps
def timed_cache(seconds):
def decorator(func):
cache = {}
@wraps(func)
def wrapper(*args, **kwargs):
key = (args, frozenset(kwargs.items()))
if key in cache:
value, timestamp = cache[key]
if time.time() - timestamp < seconds:
return value
result = func(*args, **kwargs)
cache[key] = (result, time.time())
return result
return wrapper
return decorator
@timed_cache(10) # 缓存10秒
def expensive_api_call(user_id):
print(f"执行昂贵的API调用,用户ID: {user_id}")
return f"用户{user_id}的数据"
11.3 基于闭包的状态管理
使用闭包实现状态机:
python复制def create_state_machine(initial_state):
state = initial_state
def transition(new_state):
nonlocal state
old_state = state
state = new_state
print(f"状态从 {old_state} 变为 {state}")
def current_state():
return state
return transition, current_state
# 使用状态机
change_state, get_state = create_state_machine("idle")
change_state("running") # 输出: 状态从 idle 变为 running
change_state("stopped") # 输出: 状态从 running 变为 stopped
print(get_state()) # 输出: stopped
12. 常见问题与解决方案
12.1 可变默认参数问题
问题重现:
python复制def append_to(element, target=[]):
target.append(element)
return target
print(append_to(1)) # [1]
print(append_to(2)) # [1, 2] - 不是预期的[2]
解决方案:
python复制def append_to(element, target=None):
if target is None:
target = []
target.append(element)
return target
12.2 闭包变量绑定时机
问题重现:
python复制functions = []
for i in range(3):
def func():
return i
functions.append(func)
print([f() for f in functions]) # 输出[2, 2, 2]而不是预期的[0, 1, 2]
解决方案:
python复制functions = []
for i in range(3):
def make_func(x):
def func():
return x
return func
functions.append(make_func(i))
print([f() for f in functions]) # 正确输出[0, 1, 2]
12.3 装饰器保留元信息
问题:使用装饰器后,原函数的__name__、__doc__等元信息会丢失
解决方案:使用functools.wraps
python复制from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""包装函数的文档字符串"""
return func(*args, **kwargs)
return wrapper
@my_decorator
def example():
"""示例函数的文档字符串"""
pass
print(example.__name__) # 输出: example
print(example.__doc__) # 输出: 示例函数的文档字符串
12.4 生成器耗尽问题
问题:生成器只能迭代一次,再次迭代不会产生任何值
python复制numbers = (x for x in range(3))
print(list(numbers)) # [0, 1, 2]
print(list(numbers)) # []
解决方案:
- 重新创建生成器
- 将生成器转换为列表(如果数据量不大)
- 使用itertools.tee分割生成器
python复制import itertools
numbers = (x for x in range(3))
numbers1, numbers2 = itertools.tee(numbers, 2)
print(list(numbers1)) # [0, 1, 2]
print(list(numbers2)) # [0, 1, 2]
13. Python函数进阶实战技巧
13.1 动态创建函数
Python允许在运行时动态创建函数:
python复制def create_adder(n):
def adder(x):
return x + n
return adder
add5 = create_adder(5)
print(add5(10)) # 15
更高级的动态函数创建:
python复制def create_math_function(op):
if op == "add":
return lambda x, y: x + y
elif op == "subtract":
return lambda x, y: x - y
else:
return lambda x, y: x * y
adder = create_math_function("add")
print(adder(3, 5)) # 8
13.2 函数组合与管道
将多个函数组合成一个新的函数:
python复制def compose(*functions):
def inner(arg):
for func in reversed(functions):
arg = func(arg)
return arg
return inner
def add5(x):
return x + 5
def multiply2(x):
return x * 2
add5_then_multiply2 = compose(multiply2, add5)
print(add5_then_multiply2(10)) # (10 + 5) * 2 = 30
13.3 上下文管理器函数
使用contextlib创建基于函数的上下文管理器:
python复制from contextlib import contextmanager
@contextmanager
def timer(name):
import time
start = time.time()
try:
yield
finally:
print(f"{name} 耗时: {time.time() - start:.2f}秒")
with timer("计算过程"):
sum(x ** 2 for x in range(1000000))
13.4 函数柯里化
柯里化是将多参数函数转换为一系列单参数函数的技术:
python复制def curry(func):
def curried(*args, **kwargs):
if len(args) + len(kwargs) >= func.__code__.co_argcount:
return func(*args, **kwargs)
return lambda *more_args, **more_kwargs: curried(
*(args + more_args),
**{**kwargs, **more_kwargs}
)
return curried
@curry
def add_three_numbers(a, b, c):
return a + b + c
print(add_three_numbers(1)(2)(3)) # 6
print(add_three_numbers(1, 2)(3)) # 6
print(add_three_numbers(1)(2, 3)) # 6
14. Python函数内部机制
14.1 函数对象属性
Python函数是对象,拥有许多有用的属性:
python复制def example(a, b=1, *args, **kwargs):
"""示例函数"""
return a + b
# 查看函数属性
print(example.__name__) # example
print(example.__doc__) # 示例函数
print(example.__module__) # __main__
print(example.__defaults__) # (1,)
print(example.__code__.co_varnames) # ('a', 'b', 'args', 'kwargs')
14.2 字节码分析
使用dis模块查看函数的字节码:
python复制import dis
def add(a, b):
return a + b
dis.dis(add)
输出:
code复制 2 0 LOAD_FAST 0 (a)
2 LOAD_FAST 1 (b)
4 BINARY_ADD
6 RETURN_VALUE
理解字节码可以帮助优化关键函数。
14.3 闭包变量存储
闭包的变量存储在__closure__属性中:
python复制def outer(x):
def inner():
return x
return inner
closure = outer(10)
print(closure.__closure__[0].cell_contents) # 10
14.4 函数签名检查
使用inspect模块获取函数签名信息:
python复制import inspect
def example(a, b=1, *args, **kwargs):
pass
sig = inspect.signature(example)
print(sig) # (a, b=1, *args, **kwargs)
for name, param in sig.parameters.items():
print(f"{name}: {param.default}")
15. 函数式编程实践
15.1 不可变数据结构
函数式编程强调不可变性,可以使用tuple和frozenset:
python复制def process_data(data):
# 假设data是不可变的
return tuple(x * 2 for x in data)
original = (1, 2, 3)
processed = process_data(original)
print(original) # (1, 2, 3) - 未被修改
print(processed) # (2, 4, 6)
15.2 高阶函数应用
使用高阶函数处理数据:
python复制from functools import reduce
def pipeline(data, *functions):
return reduce(lambda d, f: f(d), functions, data)
def double(xs):
return [x * 2 for x in xs]
def square(xs):
return [x ** 2 for x in xs]
def filter_evens(xs):
return [x for x in xs if x % 2 == 0]
numbers = [1, 2, 3, 4, 5]
result = pipeline(numbers, double, square, filter_evens)
print(result) # [16, 64]
15.3 递归函数优化
使用递归时注意Python的递归深度限制(默认1000):
python复制import sys
sys.setrecursionlimit(2000) # 提高递归限制
def factorial(n, acc=1):
if n == 0:
return acc
return factorial(n - 1, acc * n)
print(factorial(5)) # 120
对于深度递归,可以考虑使用尾递归优化或转为迭代实现。
15.4 惰性求值模式
利用生成器实现惰性求值:
python复制def lazy_read_lines(file):
with open(file) as f:
while True:
line = f.readline()
if not line:
break
yield line
# 不会立即读取整个文件
lines = lazy_read_lines("large_file.txt")
# 只在需要时处理
for line in lines:
if "error" in line.lower():
print(line)
16. 函数与面向对象编程
16.1 函数作为对象方法
函数可以作为对象的方法使用:
python复制class Calculator:
def __init__(self, initial=0):
self.value = initial
def add(self, x):
self.value += x
return self
def subtract(self, x):
self.value -= x
return self
def get(self):
return self.value
calc = Calculator()
result = calc.add(5).subtract(3).add(10).get()
print(result) # 12
16.2 __call__方法实现函数式对象
通过实现__call__方法,可以让对象像函数一样被调用:
python复制class Power:
def __init__(self, exponent):
self.exponent = exponent
def __call__(self,
