1. 为什么函数是Python编程的基石
第一次接触Python时,我像大多数初学者一样把所有代码堆在全局作用域里。直到某个深夜调试一个200行的脚本时,突然意识到自己正在重复复制粘贴几乎相同的代码块——那一刻我真正理解了函数的价值。
函数(function)是Python中封装代码逻辑的基本单元,它通过def关键字定义,可以接收输入参数并返回处理结果。就像乐高积木的标准化模块,良好的函数设计能让代码获得以下关键能力:
- 避免重复:相同逻辑只需编写一次,通过多次调用实现复用
- 逻辑隔离:每个函数专注解决一个特定问题,降低复杂度
- 易于维护:修改只需调整函数内部,不影响其他代码
- 团队协作:通过函数接口约定责任边界
python复制# 典型函数结构示例
def calculate_circle_area(radius):
"""计算圆的面积"""
area = 3.14159 * radius ** 2
return area
2. 函数定义的核心要素解析
2.1 函数声明语法详解
一个完整的函数定义包含以下必需部分:
python复制def function_name(parameters):
"""docstring"""
# 函数体
return value
- def:定义函数的关键字,不可省略
- 函数名:遵循变量命名规则,建议使用snake_case风格
- 参数列表:可接收零个或多个参数,用逗号分隔
- 冒号:标识函数头结束,不可遗漏
- 文档字符串:用三引号包裹的函数说明(强烈建议添加)
- 函数体:缩进的代码块,实现具体功能
- return:可选,用于返回结果。无return语句时默认返回None
经验:在PyCharm等IDE中,输入三个引号后按回车会自动生成docstring模板。良好的文档应说明函数用途、参数含义和返回值。
2.2 参数传递的四种方式
Python支持灵活的传参方式,这是其函数设计的精妙之处:
-
位置参数:最常见的传参方式,按顺序匹配
python复制def greet(name, message): print(f"{name}, {message}") greet("Alice", "Good morning!") # 正确顺序 -
关键字参数:通过参数名指定,顺序无关
python复制greet(message="How are you?", name="Bob") -
默认参数:定义时指定默认值,调用时可省略
python复制def power(base, exponent=2): return base ** exponent print(power(3)) # 使用默认exponent=2 print(power(2, 4)) # 覆盖默认值 -
可变参数:
*args:接收任意数量的位置参数,打包为元组**kwargs:接收任意数量的关键字参数,打包为字典
python复制def record(*scores, **info): print("Scores:", scores) print("Info:", info) record(85, 92, 78, student="Alice", class="Math")
避坑指南:默认参数必须指向不可变对象。若默认值为列表等可变对象,所有调用将共享同一个对象!
2.3 返回值的高级用法
Python函数返回机制有几个值得注意的特性:
-
多值返回:实际返回的是元组打包
python复制def analyze_data(data): avg = sum(data)/len(data) mx = max(data) return avg, mx # 实际上是返回元组(avg, mx) average, maximum = analyze_data([1,5,3]) # 元组解包 -
提前返回:函数可以在任意位置通过return退出
python复制def is_positive(n): if n <= 0: return False # 提前退出 # 复杂处理逻辑... return True -
返回函数:函数可以作为返回值(闭包基础)
python复制def multiplier(factor): def multiply(x): return x * factor return multiply double = multiplier(2) print(double(5)) # 输出10
3. 函数调用的实战技巧
3.1 调用栈与作用域规则
理解函数调用时的内存管理机制至关重要:
- 调用栈:每次函数调用会创建新的栈帧,存储局部变量
- 作用域查找顺序:LEGB规则
- Local(局部作用域)
- Enclosing(闭包函数外的函数)
- Global(模块全局)
- Built-in(Python内置)
python复制x = "global"
def outer():
x = "enclosing"
def inner():
x = "local"
print(x) # 输出"local"
inner()
outer()
print(x) # 输出"global"
调试技巧:使用
locals()和globals()函数可以查看当前作用域的变量字典。
3.2 递归函数的正确姿势
递归是函数调用自身的特殊形式,需注意:
- 基准条件:必须存在终止条件
- 问题分解:每次递归应减小问题规模
- 性能考量:Python默认递归深度限制为1000
python复制def factorial(n):
if n == 1: # 基准条件
return 1
return n * factorial(n-1) # 问题规模减小
对于深度递归问题,建议改用循环或使用functools.lru_cache实现记忆化:
python复制from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
3.3 Lambda表达式:匿名函数的妙用
lambda用于创建小型匿名函数,语法为lambda 参数: 表达式。典型场景:
-
排序键函数:
python复制students = [("Alice", 88), ("Bob", 95)] students.sort(key=lambda x: x[1], reverse=True) -
高阶函数参数:
python复制numbers = [1, 2, 3] squared = list(map(lambda x: x**2, numbers))
注意:复杂逻辑应使用常规函数,lambda只适合简单操作。PEP8建议lambda表达式不超过一个表达式。
4. 提升函数质量的进阶实践
4.1 类型注解与静态检查
Python 3.5+支持类型提示(type hints),虽不影响运行但能提升代码质量:
python复制from typing import List, Tuple
def process_items(items: List[str], count: int) -> Tuple[int, float]:
"""处理字符串列表并返回统计结果"""
# 函数实现...
return len(items), 0.5
配合mypy等工具可以在开发阶段捕获类型错误:
bash复制pip install mypy
mypy your_script.py
4.2 函数装饰器的魔力
装饰器是在不修改原函数代码的情况下增强函数行为的语法糖:
python复制def log_time(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"{func.__name__}执行耗时: {time.time()-start:.4f}s")
return result
return wrapper
@log_time
def heavy_calculation():
# 复杂计算...
time.sleep(2)
Python内置常用装饰器:
@property:定义属性访问方法@classmethod:定义类方法@staticmethod:定义静态方法
4.3 单元测试保障函数质量
为关键函数编写测试用例是专业开发的标配:
python复制import unittest
def add(a, b):
return a + b
class TestMath(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2,3), 5)
self.assertEqual(add(-1,1), 0)
with self.assertRaises(TypeError):
add("2", 3)
if __name__ == "__main__":
unittest.main()
使用pytest框架可以获得更简洁的测试代码:
python复制# test_math.py
def test_add():
assert add(2,3) == 5
assert add(-1,1) == 0
5. 函数设计的最佳实践
5.1 单一职责原则
优秀函数应遵循SOLID原则中的单一职责:
-
反面案例:
python复制def process_data(data): # 验证数据 if not isinstance(data, list): raise TypeError # 清洗数据 cleaned = [x.strip() for x in data] # 分析数据 avg = sum(cleaned)/len(cleaned) # 保存结果 with open("result.txt", "w") as f: f.write(str(avg)) return avg -
优化版本:
python复制def validate_data(data): if not isinstance(data, list): raise TypeError return [x.strip() for x in data] def analyze_data(cleaned_data): return sum(cleaned_data)/len(cleaned_data) def save_result(result): with open("result.txt", "w") as f: f.write(str(result))
5.2 合理的函数规模
根据Google Python风格指南建议:
- 大多数函数应控制在20行以内
- 超过40行的函数需要特别理由
- 过长的函数应拆分为多个辅助函数
检查函数长度的方法:
python复制import inspect
def func_length(func):
lines = inspect.getsourcelines(func)[0]
return len(lines)
print(func_length(process_data))
5.3 错误处理策略
健壮的函数应妥善处理异常情况:
-
防御性编程:
python复制def safe_divide(a, b): if b == 0: return float('nan') return a / b -
异常处理:
python复制def load_config(filepath): try: with open(filepath) as f: return json.load(f) except FileNotFoundError: print(f"警告:配置文件{filepath}不存在") return {} except json.JSONDecodeError: print("错误:配置文件格式无效") raise # 重新抛出异常 -
自定义异常:
python复制class InvalidInputError(Exception): pass def validate_input(value): if not value: raise InvalidInputError("输入不能为空")
6. 函数性能优化技巧
6.1 避免不必要的计算
利用缓存机制存储昂贵计算结果:
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)
对于实例方法,可以使用@cached_property:
python复制from django.utils.functional import cached_property
class DataProcessor:
@cached_property
def processed_data(self):
# 昂贵的计算过程
return result
6.2 选择高效的数据结构
函数内部数据结构选择显著影响性能:
python复制# 列表 vs 集合成员检查
def check_duplicates(items):
seen = set() # 集合的in操作是O(1)
for item in items:
if item in seen: # 比列表的O(n)快得多
return True
seen.add(item)
return False
6.3 利用生成器处理大数据
对于可能消耗大量内存的数据处理,使用生成器函数:
python复制def read_large_file(file_path):
with open(file_path) as f:
for line in f:
yield line.strip()
# 逐行处理,不一次性加载整个文件
for line in read_large_file("huge.log"):
process(line)
7. 函数式编程实践
7.1 高阶函数应用
Python内置的高阶函数典范:
-
map:应用函数到序列每个元素
python复制numbers = [1, 2, 3] squared = list(map(lambda x: x**2, numbers)) -
filter:筛选满足条件的元素
python复制even = list(filter(lambda x: x%2==0, range(10))) -
reduce:累积计算(需从functools导入)
python复制from functools import reduce product = reduce(lambda x,y: x*y, [1,2,3,4]) # 24
7.2 闭包与工厂函数
闭包(closure)是携带外部状态的函数:
python复制def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
c1 = make_counter()
print(c1()) # 1
print(c1()) # 2
7.3 偏函数应用
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(3)) # 27
8. 函数调试与性能分析
8.1 使用pdb调试
Python内置调试器基本命令:
python复制import pdb
def buggy_function(x):
pdb.set_trace() # 设置断点
result = x * 2
return result + 1
常用pdb命令:
n(next):执行下一行s(step):进入函数调用c(continue):继续执行到下一个断点p(print):打印变量值l(list):显示当前代码位置q(quit):退出调试
8.2 性能分析工具
-
timeit模块:测量小代码段执行时间
python复制import timeit timeit.timeit('"-".join(str(n) for n in range(100))', number=10000) -
cProfile:分析函数调用耗时
python复制import cProfile cProfile.run('my_function()') -
line_profiler:逐行分析性能
python复制@profile def slow_function(): # ... # 运行:kernprof -l -v script.py
9. 函数在项目中的组织方式
9.1 模块化设计
合理的函数组织原则:
- 相关函数放在同一模块(.py文件)中
- 按功能而非类型组织(如
database.py而非utils.py) - 模块大小控制在300-500行以内
示例结构:
code复制project/
├── data/
│ ├── load.py # 数据加载函数
│ └── clean.py # 数据清洗函数
├── models/
│ └── train.py # 训练相关函数
└── utils/
└── plot.py # 可视化函数
9.2 包(package)的组织
大型项目应使用包结构:
code复制mypackage/
├── __init__.py
├── submodule1.py
└── submodule2/
├── __init__.py
└── core.py
导入方式选择:
python复制# 绝对导入(推荐)
from mypackage.submodule2.core import important_function
# 相对导入(包内部使用)
from ..submodule1 import helper
9.3 入口函数模式
通过if __name__ == '__main__'区分导入与直接执行:
python复制def main():
# 实际业务逻辑
pass
if __name__ == '__main__':
main() # 直接执行时运行
使用argparse处理命令行参数:
python复制import argparse
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('--input', required=True)
return parser.parse_args()
def main():
args = parse_args()
process(args.input)
10. 函数设计的常见误区与解决方案
10.1 过度使用全局变量
问题:函数隐式依赖全局状态,导致难以测试和维护
解决方案:
- 将依赖显式作为参数传入
- 使用类封装相关状态
- 必要时使用闭包管理状态
python复制# 不良实践
config = {}
def process_data(data):
return data * config['factor']
# 改进方案
def process_data(data, factor):
return data * factor
10.2 函数副作用过多
问题:函数除了返回值外,还修改外部状态
解决方案:
- 纯函数:相同输入总是产生相同输出
- 隔离副作用:将I/O操作集中在特定函数中
- 使用副本避免修改输入参数
python复制# 不良实践
def update_stats(user, data):
user.clicks += 1 # 修改外部对象
data.append(time.time()) # 修改输入参数
return process(data)
# 改进方案
def update_stats(user_clicks, data_copy):
new_clicks = user_clicks + 1
new_data = process(data_copy)
return new_clicks, new_data
10.3 参数设计不合理
问题:参数过多或结构不清晰
解决方案:
- 参数数量控制在7个以内(心理学研究表明这是短期记忆的极限)
- 相关参数组合为字典或数据类
- 使用
**kwargs接收可选参数时明确说明有效键
python复制# 不良实践
def create_user(name, age, email, phone, address,
is_admin, is_verified, registration_date):
...
# 改进方案
from dataclasses import dataclass
@dataclass
class UserInfo:
name: str
age: int
email: str
phone: str = None
is_admin: bool = False
def create_user(user_info: UserInfo):
...
11. Python函数的未来发展
11.1 类型系统的增强
Python类型注解持续进化:
- Python 3.10引入
|语法表示联合类型 - 类型检查器支持越来越完善
- 静态类型生态逐渐丰富(mypy、pyright等)
python复制def parse_input(value: str | bytes) -> int | float:
try:
return int(value)
except ValueError:
return float(value)
11.2 模式匹配的应用
Python 3.10引入的模式匹配(structural pattern matching)为函数设计带来新范式:
python复制def handle_command(command):
match command.split():
case ["load", filename]:
load_file(filename)
case ["save", filename]:
save_file(filename)
case ["exit" | "quit"]:
shutdown()
case _:
print("Unknown command")
11.3 异步函数的普及
随着异步编程的普及,async/await语法成为现代Python开发必备技能:
python复制async def fetch_data(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.json()
async def process_multiple(urls):
tasks = [fetch_data(url) for url in urls]
return await asyncio.gather(*tasks)
12. 函数优化的量化分析
12.1 时间复杂度对比
常见操作的时间复杂度:
| 操作 | 列表 | 集合 | 字典 |
|---|---|---|---|
| 查找元素 | O(n) | O(1) | O(1) |
| 插入元素 | O(1) | O(1) | O(1) |
| 删除元素 | O(n) | O(1) | O(1) |
优化示例:
python复制# O(n^2)版本
def find_duplicates_v1(items):
duplicates = []
for i in range(len(items)):
if items[i] in items[i+1:]: # O(n)操作
duplicates.append(items[i])
return duplicates
# O(n)版本
def find_duplicates_v2(items):
seen = set()
duplicates = set()
for item in items:
if item in seen: # O(1)操作
duplicates.add(item)
seen.add(item)
return list(duplicates)
12.2 内存占用分析
使用sys.getsizeof()检查对象内存占用:
python复制import sys
def test_memory():
small_list = list(range(10))
large_list = list(range(1000000))
print(f"小列表: {sys.getsizeof(small_list)} bytes")
print(f"大列表: {sys.getsizeof(large_list)} bytes")
# 生成器节省内存
gen = (x for x in range(1000000))
print(f"生成器: {sys.getsizeof(gen)} bytes")
12.3 性能优化决策树
函数性能优化路径参考:
code复制开始
│
├─ 算法复杂度是否最优? → 否 → 选择更优算法
│ → 是 ↓
├─ 是否频繁计算相同结果? → 是 → 添加缓存
│ → 否 ↓
├─ 数据结构是否合适? → 否 → 更换数据结构
│ → 是 ↓
├─ 是否有向量化操作可能? → 是 → 使用NumPy等库
│ → 否 ↓
├─ 是否涉及I/O瓶颈? → 是 → 考虑异步/多线程
│ → 否 ↓
└─ 是否需要更低级优化? → 是 → 考虑Cython等
→ 否 → 优化完成
13. 函数文档与协作规范
13.1 文档字符串标准
遵循PEP257规范的docstring示例:
python复制def calculate_stats(data):
"""计算数据集的统计指标
参数:
data (list): 包含数值的列表,不支持空列表
返回:
dict: 包含以下键的字典:
- 'mean' (float): 算术平均值
- 'median' (float): 中位数
- 'std_dev' (float): 标准差
异常:
ValueError: 当输入为空列表时引发
示例:
>>> calculate_stats([1, 2, 3])
{'mean': 2.0, 'median': 2.0, 'std_dev': 0.816...}
"""
if not data:
raise ValueError("输入数据不能为空")
# 实现代码...
13.2 类型注解规范
现代Python项目推荐的类型注解风格:
python复制from typing import Optional, Union, List, Dict
def process_records(
records: List[Dict[str, Union[int, float]]],
threshold: Optional[float] = None
) -> Dict[str, float]:
"""处理记录数据并返回统计结果
参数:
records: 字典列表,每个字典包含数值数据
threshold: 可选的过滤阈值,为None时不过滤
返回:
包含各种统计指标的字典
"""
# 实现代码...
13.3 版本变更记录
在文档字符串中记录重大变更:
python复制def legacy_function(param):
"""执行某项操作
注意:
此函数已过时,将在v2.0移除,请使用new_function代替
变更记录:
v1.0: 初始版本
v1.5: 添加param参数支持
v1.8: 标记为过时
"""
warnings.warn("legacy_function将在v2.0移除", DeprecationWarning)
# 旧实现...
14. 函数与面向对象编程
14.1 方法与函数的区别
类方法本质上仍是函数,但有以下关键区别:
| 特性 | 普通函数 | 类方法 |
|---|---|---|
| 定义位置 | 模块级 | 类内部 |
| 第一个参数 | 自定义 | 通常为self或cls |
| 访问权限 | 无 | 可访问类成员 |
| 调用方式 | func() | obj.method() |
python复制class Calculator:
# 实例方法
def add(self, a, b):
return a + b
# 类方法
@classmethod
def create_with_version(cls, version):
instance = cls()
instance.version = version
return instance
# 静态方法
@staticmethod
def subtract(a, b):
return a - b
14.2 何时选择函数而非方法
适合使用模块函数而非类方法的场景:
- 操作不依赖或修改对象状态
- 功能是通用的、无状态的
- 需要作为高阶函数的参数
- 简单到不需要封装
python复制# 更适合作为模块函数
def format_timestamp(timestamp, fmt="%Y-%m-%d"):
return datetime.fromtimestamp(timestamp).strftime(fmt)
# 而不是类方法
class TimeUtils:
@staticmethod
def format_timestamp(timestamp, fmt):
# 不必要的封装
return datetime.fromtimestamp(timestamp).strftime(fmt)
14.3 可调用对象模拟函数
通过实现__call__方法,类实例可以像函数一样被调用:
python复制class Adder:
def __init__(self, increment):
self.increment = increment
def __call__(self, x):
return x + self.increment
add5 = Adder(5)
print(add5(3)) # 输出8
这种模式常用于:
- 需要维护状态的函数
- 装饰器类实现
- 策略模式的具体策略
15. Python内置函数深度解析
15.1 高频内置函数详解
部分核心内置函数的底层原理:
-
range():实际返回的是range对象,不是列表
python复制r = range(10) # 不立即生成所有数字 print(list(r)[3]) # 按需计算 -
zip():惰性求值,内存高效
python复制names = ["Alice", "Bob"] scores = [85, 92] paired = zip(names, scores) # 不立即生成所有元组 -
sorted():使用TimSort算法,稳定排序
python复制data = ["apple", "Banana", "cherry"] sorted(data, key=lambda x: x.lower()) # 大小写不敏感排序
15.2 函数工具库应用
functools模块提供的强大工具:
-
partial:固定部分参数
python复制from functools import partial basetwo = partial(int, base=2) basetwo('10010') # 18 -
reduce:累积计算
python复制from functools import reduce factorial = lambda n: reduce(lambda x,y: x*y, range(1,n+1)) -
total_ordering:自动生成比较方法
python复制from functools import total_ordering @total_ordering class Student: def __init__(self, score): self.score = score def __eq__(self, other): return self.score == other.score def __lt__(self, other): return self.score < other.score
15.3 运算符模块妙用
operator模块提供函数式运算符:
python复制from operator import itemgetter, attrgetter, methodcaller
# 数据排序
students = [("Alice", 88), ("Bob", 95)]
sorted(students, key=itemgetter(1)) # 按分数排序
# 属性访问
get_name = attrgetter('name')
get_name(student) # 等价于student.name
# 方法调用
uppercase = methodcaller('upper')
uppercase('hello') # 'HELLO'
16. 函数测试的完整方案
16.1 单元测试框架
unittest模块的基本用法:
python复制import unittest
def divide(a, b):
if b == 0:
raise ValueError("除数不能为零")
return a / b
class TestMathFunctions(unittest.TestCase):
def test_divide_normal(self):
self.assertAlmostEqual(divide(5, 2), 2.5)
def test_divide_by_zero(self):
with self.assertRaises(ValueError):
divide(5, 0)
@unittest.skip("暂时跳过")
def test_negative(self):
self.assertEqual(divide(-4, 2), -2)
if __name__ == '__main__':
unittest.main()
16.2 参数化测试
使用parameterized实现多组输入测试:
python复制from parameterized import parameterized
import unittest
class TestStringMethods(unittest.TestCase):
@parameterized.expand([
("empty", "", 0),
("single", "a", 1),
("multiple", "abc", 3),
])
def test_length(self, name, input_str, expected):
self.assertEqual(len(input_str), expected)
16.3 测试覆盖率检查
使用coverage.py测量测试覆盖率:
bash复制# 安装
pip install coverage
# 运行测试并收集覆盖率
coverage run -m unittest discover
# 生成报告
coverage report -m
典型输出:
code复制Name Stmts Miss Cover Missing
---------------------------------------------
my_module.py 45 5 89% 15-19, 32
test_module.py 20 0 100%
---------------------------------------------
TOTAL 65 5 92%
17. 函数部署与性能调优
17.1 编译优化选项
使用__slots__减少内存占用:
python复制class DataPoint:
__slots__ = ['x', 'y'] # 限制允许的属性
def __init__(self, x, y):
self.x = x
self.y = y
17.2 函数级性能优化
使用dis模块查看字节码:
python复制import dis
def test():
x = [i for i in range(10)]
return sum(x)
dis.dis(test)
输出示例:
code复制 2 0 LOAD_CONST 1 (<code object <listcomp> at 0x...>)
2 LOAD_CONST 2 ('test.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (range)
8 LOAD_CONST 3 (10)
10 CALL_FUNCTION 1
12 GET_ITER
14 CALL_FUNCTION 1
16 STORE_FAST 0 (x)
...
17.3 多进程并行处理
multiprocessing.Pool加速CPU密集型任务:
python复制from multiprocessing import Pool
def process_chunk(chunk):
# 处理数据块
return result
def parallel_process(data, chunksize=1000):
with Pool() as pool:
results = pool.map(process_chunk,
[data[i:i+chunksize]
for i in range(0, len(data), chunksize)])
return combine_results(results)
18. 函数安全最佳实践
18.1 输入验证模式
防御性编程的关键要点:
python复制def safe_eval(expression, allowed_vars=None):
"""安全评估数学表达式"""
if not isinstance(expression, str):
raise TypeError("表达式必须是字符串")
if allowed_vars is None:
allowed_vars = {}
# 检查表达式只包含安全字符
allowed_chars = set("0123456789+-*/(). ")
if not set(expression) <= allowed_chars:
raise ValueError("表达式包含不安全字符")
try:
return eval(expression, {"__builtins__": None}, allowed_vars)
except Exception as e:
raise ValueError(f"评估失败: {str(e)}")
18.2 敏感数据处理
安全处理密码等敏感信息:
python复制def get_password():
"""安全获取密码输入"""
import getpass
password = getpass.getpass("请输入密码: ")
if not password:
raise ValueError("密码不能为空")
return password
def clean_sensitive_data(data):
"""安全擦除敏感数据"""
if isinstance(data, (str, bytes)):
# 用随机数据覆盖内存
import os
if isinstance(data, str):
data = data.encode('utf-8')
length = len(data)
data = os.urandom(length)
data = b'\x00' * length
return None
18.3 沙箱执行环境
限制不可信代码的执行:
python复制def safe_execute(code, timeout=1):
"""在受限环境中执行代码"""
from contextlib import redirect_stdout
import io
# 限制可访问的全局变量
restricted_globals = {
'__builtins__': {
'range': range,
'len': len,
# 其他白名单函数...
}
}
output = io.StringIO()
try:
with redirect_stdout(output):
exec(code, restricted_globals)
except Exception as e:
return f"执行错误: {str(e)}"
return output.getvalue()
19. 函数式设计模式实战
19.1 策略模式实现
使用函数作为策略对象:
python复制def linear_search(items, target):
for i, item in enumerate(items):
if item == target:
return i
return -1
def binary_search(sorted_items, target):
low, high = 0, len(sorted_items)-1
while low <= high:
mid = (low + high) // 2
if sorted_items[mid] == target:
return mid
elif sorted_items[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
class SearchEngine:
def __init__(self, strategy=linear_search):
self.strategy = strategy
def search(self, items, target):
return self.strategy(items, target)
# 使用
engine = SearchEngine()
print(engine.search([1,5,3], 5)) # 线性搜索
engine.strategy = binary_search
print(engine.search([1,3,5], 3)) # 二分搜索
19.2 装饰器模式应用
动态添加功能:
python复制def log_call(func):
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__},参数: {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"调用完成,返回: {result}")
return result
return wrapper
def validate_input(func):
def wrapper(text):
if not isinstance(text, str):
raise TypeError("输入必须是字符串")
if not text.strip():
raise ValueError("输入不能为空")
return func(text)
return wrapper
@log_call
@validate_input
def process_text(text):
return text.upper()
process_text("hello") # 会先验证再记录日志