Python:哪个代码“更好”?

时间:2013-07-01 16:10:36

标签: python performance if-statement exception-handling coding-style

我构建了这两段代码,我想知道哪些是“更好”。由此我不一定意味着哪一个更快执行,因为这不是我的程序的关注。哪一个更具可读性?

或者:

A = 1
B = some_other_value
try:
    A /= B
except ZeroDivisionError:
    pass

或者:

A = 1
B = some_other_value
if B != 0:
    A /= B

3 个答案:

答案 0 :(得分:2)

第二个可能更具可读性,但第一个允许更大的多态性和鸭子类型(在B不是floatint的情况下,但是支持除法的对象)。

此处的大多数讨论似乎都忽略了 B可能支持分组的自定义对象。考虑以下以NumType类作为分母的exapmles。

>>> class NumType(object):  # basically, an int wrapper
...     """Custom number type.  Supports division when it is the denominator"""
...     def __init__(self, val):              
...             self.val = val
...     def __rdiv__(self, num):
...             return num / self.val
... 
>>> c = NumType(1)  #normal division works as expected
>>> 5 / c
5
>>> c = NumType(7)
>>> 5. / c
0.7142857142857143
>>> c = NumType(0)
>>> 5 / c  # 0 division causes exception
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __rdiv__
ZeroDivisionError: integer division or modulo by zero
>>> # pay attention here:
>>> if c != 0:  # condition is True because c is an object, not 0
...     print 5 / c  # so this division still occurs, and generates an exception
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 5, in __rdiv__
ZeroDivisionError: integer division or modulo by zero
>>> # however, this is caught with a try/except
>>> try:
...     5 / c
... except ZeroDivisionError:
...     print '0 division'
... 
0 division

答案 1 :(得分:1)

当然第二个:

A = 1
B = some_other_value
if B != 0:
    A /= B

不是因为它更具可读性,而是因为你没有在异常条件下使用异常。如果在正常情况下可能出现无效输入或可能导致错误的输入,那么您绝不应该使用异常来处理它。

你可以在网上找到关于这方面的非常好的解释,但在我看来(除了表现)总是因为意图:当你处理异常时,你会向读者清楚说明它是<强>异常情况,这是一个错误,在正常的程序流程中不应该发生。在您的情况下不是因为无效输入是绝对可能的(必须始终验证每个输入)

从我的角度来看,你想要处理它的事实意味着它是可能的,然后检查始终是正确的解决方案。就像Ryan所说,如果你不必检查零,你可能有更高的多态性,那么你要做的就是将检查移动到可以处理这种情况的地方(例如在/运算符中,而不是在你使用它的地方) )。

修改
几句话更总结我写的评论。 Python鼓励一种名为EAFP的编程风格,当你编写小脚本时,这是一个很好的资源,但在编写应用程序和库时应该小心使用它。

有助于保持代码简短(并且快速用于最常见的代码路径),但它有一个大劣势:如果你不喜欢要包含try / execpt每一行,你必须处理中间结果和部分计算。一个大的try可能会使应用程序处于不确定状态(或者它只会使您的代码更不易读,因为很长的列表 - 可能是嵌套的 - try / except / {{1 }} / else)。

我同意在您甚至没有想到的情况下使用您的代码会有所帮助,但不灵活脆弱。对于一个简短的个人脚本可能没问题但是如果我编写一个应用程序(或者更多的是一个库)我想确定我的代码在哪里以及如何失败,我会编写测试来检查它是如何工作的不同输入。我不希望它以我无法预测的方式失败,意外输入&gt;意外行为听起来太像垃圾输入&gt;垃圾输出。应用程序必须健壮。在检查了所有可以查看的内容之后,您甚至必须为特殊情况做好准备(我可以放松这个规则,以便在极少数情况下检查可能是偏执的。)

答案 2 :(得分:0)

答案是:这取决于。

是否可以轻松编写适当的测试来处理条件。在这种情况下,你可以。

另一个考虑因素是您的手写测试是否足够。在一行代码中,这很容易。如果你有许多操作,那么假设一切都很好可能更有意义,并在事后用异常来解决。 (当然,在这种情况下,输入验证通常可能更有用)。

与编程中的大多数事情一样,这是风格和品味的问题。在python中尤其如此,它通常有多种处理方式(尽管你可能已阅读过任何复活节彩蛋),并且主要基于程序员能够做出自己决定的想法(不像Java,确实尝试强制执行单一的编程风格,通过使一切意外变得比预期的技术更难和更令人不愉快。

想想你在做什么以及为什么。尽量不要重复自己。