在Python中完全禁用/替换ZeroDivisionError

时间:2014-01-19 14:50:19

标签: python error-handling divide-by-zero

美好的一天。 我一直在搜索相关的帖子,但没有得到我想要找到的理想解决方案。让我来描述我的问题:

我正在分析语料库中的文本,从这些文本中提取特征,然后将特征存储在数组中。这些特征中的一些涉及比率,例如男性代词的比例"他"对于femenine代词"她"。问题是,对于某些变量,值将为零,并且它们将引发ZeroDivisionError。

由于我计算了大约100个这样的比率,围绕每个比率计算包装try / catch异常听起来太麻烦了。

我发现我可以做到

#16,RATIO_masculine_femenine
feature_map.append(numOfHe / numOfShe if numOfShe else 0)

但它仍然有点过于费力。 我想知道是否有办法在脚本开始时声明任何ZeroDivisionError应该被NaN或0替换,或者任何其他可能适合的值。

由于

2 个答案:

答案 0 :(得分:0)

pythonic的答案是将它包装在一个函数中,例如:

def ratio(a, b):
    if b == 0:
        return 0
    else:
        return a / b

feature_map.append(ratio(numOfHe, numOfShe))

函数的确切形式取决于你们其余的代码,但是如果你写了几百行,那么你应该把它包装在一个函数中,或者至少使用一个循环。此外,numOfHenumOfShe等变量名称暗示您可能会更好地为dict服务。

<强>更新

我从你的代码链接中看到每个calc实际上完全不同,所以你可能不能轻易地循环它。由于计算仍然相对简单,您可以尝试使用eval这样的技巧:

calcs = [
    ...
    (12, 'h + ha + hw + hy'),
    (13, '(h + ha) / (hw + hy)'),
    ...
]

for index, calc in calcs:
    try:
        v = eval(calc, locals())
    except ZeroDivisionError:
        v = 0
    feature_map.append(v)

您还可以向calcs添加其他信息,然后使用namedtuple。您也可以使用类来代替在需要时动态评估计算,如果有帮助的话。

答案 1 :(得分:0)

如果将int对象包装在自定义子类中,则可以解决一次:

class SafeInt(int):
    def __div__(self, y):
        try:
            return SafeInt(super(SafeInt, self).__div__(y))
        except ZeroDivisionError:
            return SafeInt(0)

覆盖所有 int s:

original_int = int
int = SafeInt
int(5) / 0
# O: 0

覆盖部分 int

SafeInt(5) / 0
# O: 0

关于保持对象为SafeInt,你必须要小心。您会注意到我在__div__内返回的所有内容都包含在SafeInt()中。 int对象是不可变的,每次都必须显式返回一个新的SafeInt对象。这意味着您可能需要为SafeInt()中的每个函数创建一个装饰器以确保这一点。我将这作为练习留给读者!

否则你最终会得到这个:

>>> SafeInt(5) / 0
0   # this is a SafeInt object
>>> _ / 0
0   # this is a SafeInt object; no error
>>> SafeInt(5) + 0
5   # this is a basic int object
>>> _ / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

最后一点说明:您可以将SafeInt作为参数传递给defaultdict,以使所有成员SafeInt


编辑:知道你希望它发生在所有 int上,我希望这样的事情可能有用,但不允许(有充分理由):

>>> def wrapdiv(olddiv):
...     def newdiv(self, y):
...         try:
...             olddiv(self, y)
...         except ZeroDivisionError:
...             return 0
...     return newdiv
...
>>> int.__div__ = wrapdiv(int.__div__)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'int'