解决Python包中的错误

时间:2011-10-31 11:02:24

标签: python package

我最近遇到了以下问题:我正在开发一个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模块,以便每个其他包只能看到修补后的包?我认为这个问题很常见,所以可能应该有一些“最佳实践”。

2 个答案:

答案 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模块,只是需要修复的部分(记住:显式优于隐式)。