您可能知道Microsoft关于在.NET中使用异常的建议:
性能注意事项
...
仅抛出异常 非凡的条件,...
此外,不要抛出异常 当返回代码足够时......
(参见http://msdn.microsoft.com/en-us/library/system.exception.aspx的全文。)
作为比较点,你会推荐相同的Python代码吗?
答案 0 :(得分:34)
pythonic要做的是提出和处理异常。优秀的书籍“简而言之的Python”在第6章的“错误检查策略”中对此进行了讨论。
这本书讨论了EAFP(“请求宽恕比允许更容易”)与LBYL(“在你跳跃之前看”)。
所以回答你的问题:
不,我不建议使用相同的python代码。我建议你阅读Python in a nutshell的第6章。
答案 1 :(得分:10)
理解例外的最佳方式是“if your method can't do what its name says it does, throw。”我个人认为,这个建议应该同样适用于.NET和Python。
关键的区别在于,您拥有的方法通常无法完成其名称所应执行的操作,例如,将字符串解析为整数或从数据库中检索记录。 C#样式是为了避免首先抛出异常:
int i;
if (Int32.TryParse(myString, out i)) {
doWhatever(i);
}
else {
doWhatever(0);
}
而Python对这种事情更加放心:
try:
i = int(myString)
except ValueError:
i = 0
doWhatever(i);
答案 2 :(得分:8)
在Python中,异常并不像其他语言那样昂贵,所以我不建议尝试避免异常。但是如果你确实抛出异常,你通常会想要在代码中的某个地方捕获它,例外情况是发生致命错误。
答案 3 :(得分:8)
通常,Python面向表达性
我会在这里应用相同的原则:通常,您希望函数返回结果(与其名称一致!)而不是错误代码。
因此,通常比返回错误代码更能引发异常。
但是,MSDN文章中所述的内容也适用于Python,它并不真正与返回错误代码而不是异常相关联。
在许多情况下,您可以看到用于正常流控制的异常处理,以及用于处理预期情况的异常处理。在某些环境中,这会对性能产生巨大影响;在所有环境中,它对程序表达能力和可维护性都有很大影响。
例外情况是异常情况,超出正常程序流程;如果你期望会发生某些事情,那么你应该直接处理,然后提出任何你不能期望/处理的东西。
当然,这不是一个配方,而只是一个启发式;最终的决定始终取决于开发人员和上下文,并且无法在一套固定的指南中说明 - 这对于异常处理来说更为真实。
答案 4 :(得分:4)
我做了一个简单的实验来比较使用以下代码提高异常的效果:
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()
得到以下结果:
return
:0.383000秒例外情况比使用return
慢8倍。
答案 5 :(得分:3)
我认为是否返回错误代码或抛出异常是非常有效的思考,跨语言比较可能会有所帮助和提供信息。我想这个问题的非常普遍的答案就是考虑:任何函数的合法返回值集合应该尽可能小,并且必要时尽可能大。
通常,这意味着如果给定方法在单个测试用例中返回整数,则用户可以正确地期望该方法始终返回整数或抛出一个例外。但是,当然,概念上最简单的方式并不总是处理事物的最佳方式。
最少惊喜的回报通常是None
;如果你研究它,你会发现它是None
的语义,它全面地使用它:它是一个单例,不可变的值,在很多情况下,它的计算结果为{{1或者禁止进一步计算 - 没有连接,没有算术。因此,如果您选择编写一个False
方法返回一个字符串输入的数字,并frob(x)
表示非数字字符串和任何其他输入,并在None
之类的表达式中使用它},你仍然得到一个非常接近虚假事件的例外。当然,如果将a=42+frob('foo')
填入尚未使用frob('foo')
定义的数据库列中,则可能在几个月后遇到问题。这可能是合理的,也可能是不合理的。
因此,在大多数情况下,例如想要从字符串中派生一个数字,使用像NOT NULL
或float(x)
之类的somwething是可行的方法,因为这些内置函数会在没有给出可消化输入的情况下引发异常。如果这不适合您的用例,请考虑从自定义方法返回int(x)
;基本上,这个返回值告诉消费者“对不起,我无法理解你的输入。” 但是如果你肯定知道你的计划中的进展从那时起就有意义,你只想这样做。
你知道,我刚刚发现了如何将每个通知,警告和错误消息转换为可能显示停止的异常,例如,PHP。它只是让我疯狂,变量名中的拼写错误会在标准的PHP配置中生成,只是通知用户。这是如此糟糕。该程序只是继续使用一个根本没有意义的程序代码!我无法相信人们会发现这是一个特色。
同样地,人们应该这样看:如果在任何给定的时间点,可以以合理的成本断言一段代码的执行没有意义 - 因为缺少值,所以边界,或者是意外类型,或者当数据库连接等资源出现故障时 - 必须最大限度地减少调试难题,将执行和手动控制分解到代码中任何感觉有权处理事故的级别。
经验表明,避免早期操作并允许虚假值进入您的数据只会让您的代码更难调试。过度热衷的类型转换的许多例子也是如此:允许将整数添加到浮点数是合理的。允许只将数字添加到数字的字符串是一种虚假的做法,可能会产生奇怪的,未本地化的错误,这些错误可能会出现在正在处理该数据的任何给定行上。