我最近遇到了以下问题:我正在开发一个Python中的数字库(称为spuq
),其核心需要scipy
。现在,scipy中的一个函数叫做btdtri
,它有一个输入参数元组的错误。然而,根据scipy的开发人员,这个bug现在已经在scipy 0.9版中修复了。所以在我的代码中我有这样的东西:
import scipy
def foo(a, b, c):
if scipy.__version__>=(0, 9):
return btdtri(a, b, c)
else:
return my_fixed_btdtri(a, b, c)
但是,我不喜欢在第三方软件包的错误修复中丢弃我的代码。我希望将其包含在一个模块中,该模块实现了变通方法,并让我的所有其他模块自动使用修补模块。
现在我的问题是:一般来说处理这类案件的最佳做法是什么?例如。写我自己的spuq.contrib.scipy
并说那里
from scipy import *
if __version__ < (0, 9):
btdtri = my_fixed_btdtri
而不是在任何地方导入scipy
导入spuq.contrib.scipy
?我认为这很复杂,容易忘记(可能是单声道和丑陋的)。也许有一种方法可以自动“挂钩”加载包并直接修改scipy
模块,以便每个其他包只能看到修补后的包?我认为这个问题很常见,所以可能应该有一些“最佳实践”。
答案 0 :(得分:5)
你可以“修补”scipy模块。在初始化代码的某处,执行
import scipy.special
if scipy.version.version < "0.9.0":
scipy.special.btdtri = my_btdtri
由于模块只导入一次,因此只有一个模块scipy.special
,所有其他模块只能看到猴子修补版本。
猴子修补通常被认为对测试很有用,但对生产代码却没有用。但是,在这种情况下,我认为这很好,因为你没有真正改变包的行为 - 你正在修复一个确认的错误。
答案 1 :(得分:1)
最好的选择是创建一个模块,比如fixes
,导出固定版本或btdtri
的外部版本,具体取决于SciPy版本,如您的示例所示。它可以做得更简单:
if scipy.version.version < (0,9,0):
def btdtri(...):
# whatever
else:
btdtri = scipy.btdtri
这比您的版本更有优势,pyflakes
等代码检查工具不会阻塞import *
,并且您无需从{{1}获取所有SciPy API模块,只是需要修复的部分(记住:显式优于隐式)。