在Python中使用exception还是返回代码更好?
您可能会从Microsoft获知有关在.NET中使用例外情况的build议:
性能考虑
…
仅在特殊情况下抛出exception…
另外,当返回码足够时,不要抛出exception。
(请参阅http://msdn.microsoft.com/en-us/library/system.exception.aspx上的全文 。
作为比较的一点,你会推荐相同的Python代码?
pythonic要做的是提出和处理exception。 这本好书“简而言之,Python”在第6章的“错误检查策略”中对此进行了讨论。
这本书讨论EAFP(“容易要求宽恕而不是许可”)与LBYL(“在你跳跃之前看”)。
所以要回答你的问题:
不,我不会推荐python代码。 我build议你简单阅读一下Python的第6章。
理解exception的最好方法是“ 如果你的方法不能做它的名字,就扔掉” 。 我个人认为,这个build议应该同时应用于.NET和Python。
关键的区别在于你有哪些方法经常不能做他们应该做的事情,比如把stringparsing为整数,或者从数据库中检索logging。 C#风格是为了避免首先抛出exception:
int i; if (Int32.TryParse(myString, out i)) { doWhatever(i); } else { doWhatever(0); }
而Python对这种事情更加放心:
try: i = int(myString) except ValueError: i = 0 doWhatever(i);
在Python中,exception并不像其他一些语言那样昂贵,所以我不build议尽量避免exception。 但是,如果你抛出一个exception,你通常想在你的代码中的某个地方捕获它,如果发生致命错误则是例外。
通常,Python是面向expression的。
我会在这里应用相同的原则:通常,你期望一个函数返回一个结果 (符合它的名字!),而不是一个错误代码。
出于这个原因,通常比返回错误代码更好地引发exception。
但是,MSDN文章中提到的内容也适用于Python,而且它并不真正连接到返回错误代码而不是exception。
在许多情况下,您可以看到用于正常stream量控制的exception处理以及处理预期的情况。 在某些环境下,这对性能有很大的影响。 在所有的环境中,它对程序的performance力和可维护性都有很大的影响。
例外情况是在正常程序stream程之外的特殊情况; 如果你期望会发生什么事情,那么你应该直接处理,然后提出任何你不能指望/处理的事情。
当然,这不是一个配方,而只是一个启发式的方法。 最终的决定总是由开发人员决定,而且不能在一套固定的指导方针中进行说明 – 这对于exception处理来说更为真实。
我做了一个简单的实验来比较引发exception的性能和下面的代码:
from functools import wraps from time import time import logging def timed(foo): @wraps(foo) def bar(*a, **kw): s = time() foo(*a, **kw) e = time() print '%f sec' % (e - s) return bar class SomeException(Exception): pass def somefunc(_raise=False): if _raise: raise SomeException() else: return @timed def test1(_reps): for i in xrange(_reps): try: somefunc(True) except SomeException: pass @timed def test2(_reps): for i in xrange(_reps): somefunc(False) def main(): test1(1000000) test2(1000000) pass if __name__ == '__main__': main()
结果如下:
- 引发例外:3.142000秒
- 使用
return
:0.383000秒
例外情况比使用return
慢大约8倍。
我认为是否要返回错误代码或抛出exception是非常有效的思考,而跨语言比较可能会有帮助和信息量。 我想这个问题的普遍回答只是考虑到: 任何函数的合法返回值都应该尽可能小,而且尽可能大 。
通常,这意味着如果一个给定的方法在单个testing用例中返回一个整数,用户可以正确地期望该方法总是返回一个整数或抛出一个exception。 但是,当然,在概念上最简单的方式并不总是处理事情的最佳方式。
最less的意外收益通常是None
; 如果你仔细研究一下,你会发现它是“ None
语义:它是一个单一的,不可改变的值,在很多情况下,评估为False
或者禁止进一步的计算。连接,没有算术。 所以,如果你select写一个返回一个stringinput的数字的frob(x)
方法,而非数字string和任何其他input的None
,并且在expression式中使用它,如a=42+frob('foo')
,你仍然得到一个非常接近虚假事件发生点的例外。 当然,如果你把frob('foo')
填入一个没有用NOT NULL
定义的数据库列中,你可能会在几个月后遇到问题。 这可能或可能不合理。
所以在大多数情况下,如果你想从一个string中得到一个数字,就像是一个纯粹的float(x)
或者int(x)
一样使用somwething,因为这些内置函数在没有可消化的时候会引发一个exceptioninput。 如果这不适合您的用例,请考虑从自定义方法返回None
; 基本上,这个回报值告诉消费者“对不起,我无法理解你的意见”。 但是 ,如果你确实知道在你的程序中继续进行,那么你只想做到这一点。
你看,我刚刚发现如何将每个通知,警告和错误消息变成一个潜在的停止例外,在PHP中。 这让我疯狂,在标准的PHPconfiguration中产生一个variables名称中的拼写错误, 除了通知用户 。 这太糟糕了。 该程序只是继续做一些没有意义的程序代码! 我不能相信人们会发现这个function。
同样,我们也应该这样看待:如果在任何特定的时间点,可以用合理的代价来断定执行一段代码是没有意义的 – 因为价值缺失,或者越界是一个意想不到的types,或者当像数据库连接这样的资源已经不存在的时候,为了减lessdebugging的麻烦,把代码中的执行和手动控制到可以处理这个事故的代码中的任何一个层次都是非常必要的。
经验表明,避免早期的行为,并允许虚假的价值观蔓延到你的数据只是使你的代码更难以debugging。 因此,过度热心的types铸造的许多例子:允许整数被添加到浮动是合理的。 要允许一个只有数字的string被添加到一个数字是一个假的做法,可能会创build奇怪的,未定位的错误,可能会出现在任何给定的线正好是处理该数据。