在Python开发中,我们经常需要使用第三方模块。为了自定义一些行为,我们可能需要对第三方模块进行扩展。本文将介绍两种常见的扩展方式:Composition(组合)
和Monkey Patch(猴子补丁)
,并比较两者的优缺点。
Composition(组合)
Composition的核心思想是,不直接修改第三方模块,而是将其封装在一个新类中,通过组合的方式实现扩展。
例如,有一个第三方模块math:
代码语言:javascript复制# math.py
def add(x, y):
return x y
def multiply(x, y):
return x * y
我们可以这样通过组合扩展它:
代码语言:javascript复制import math
class MathPlus:
def __init__(self):
self.math = math
def add(self, x, y):
return self.math.add(x, y) * 2
def multiply(self, x, y):
return self.math.multiply(x, y)
使用MathPlus时:
代码语言:javascript复制math_plus = MathPlus()
print(math_plus.add(2, 3)) # 10
这种方式的优点是:
- 不需要修改第三方模块的代码,遵循开闭原则
- 新增功能和原有功能分离清晰,扩展更加可控
- 避免了模块之间的全局变量污染等问题
- 符合组合优于继承的设计原则 缺点是:
- 需要编写额外的包装代码,增加了一些复杂度
- 对第三方模块的访问需要通过包装对象,可能带来少许运行时性能损失
Monkey Patch
Monkey Patch
机制可以在运行时动态修改模块的属性和方法,实现对模块的扩展。
例如,可以这样扩展math模块:
代码语言:javascript复制import math
# 新增一个add方法
def add(x, y):
return x y * 2
math.add = add
# 修改既有的multiply方法
def new_multiply(x, y):
return x * y * 2
math.multiply = new_multiply
使用时,math模块已经被扩展了:
代码语言:javascript复制print(math.add(2, 3)) # 8
print(math.multiply(2, 3)) # 12
这种方式的优点是:
- 语法简单,可以快速方便地扩展第三方模块
- 没有额外的封装代码,易于使用 缺点是:
- 破坏了第三方模块的封装,不安全
- 容易造成不同patch之间的冲突
- 很难重置修改,不易维护
- 多进程环境下会互相干扰
- 第三方模块更新时扩展可能会失效
总结
- Composition是一种非侵入式的扩展方式,修改是可控的,比较安全稳定。但需要额外的代码来组合模块。
- Monkey Patch直接修改第三方模块,简单方便。但可能会导致难以预料的问题,不太安全。
- Composition符合开闭原则,monkey patch破坏开闭原则。
- Composition优先于继承,monkey patch可看作一种隐形的继承。
- 对第三方模块的扩展,首先考虑Composition。如果只是临时的hack,可以使用monkey patch。
- 复杂系统应优先使用Composition,只有非侵入式扩展才能使系统模块之间相对独立、稳定可控。