“else” considered harmful in Python?
在回答(S.lott)关于python的
Actually, even on an if-statement, the
else: can be abused in truly terrible
ways creating bugs that are very hard
to find. [...]Think twice about else:. It is
generally a problem. Avoid it except
in an if-statement and even then
consider documenting the else-
condition to make it explicit.
这是一个广泛持有的观点吗?
当然,您可以用它编写令人困惑的代码,但对于任何其他语言结构来说,这是正确的。在我看来,即使是python的
洛特显然看到了一些坏代码。我们不是吗?我不认为其他有害的东西,尽管我见过它曾经写坏代码。在这些情况下,所有周围的代码都是坏的,那么为什么要怪穷人呢?
不,这不是有害的,是必要的。
应该总是有一个catch all语句。所有开关都应该有一个默认值。ML语言中的所有模式匹配都应该有一个默认值。
如果一系列的if语句是生活中的一个事实,那么就不可能推断出什么是真的了。计算机是世界上最大的有限状态机,在任何情况下列举每一种可能性都是愚蠢的。
如果你真的担心在else语句中未知的错误会被忽略,那么在那里引发异常真的那么困难吗?
我不会说这是有害的,但有时候,else语句会给你带来麻烦。例如,如果您需要基于输入值进行一些处理,并且只有两个有效的输入值。只有检查一个才能引入错误。如:
1 2 3 4 5 6 7 8 9 10 11 12 | The only valid inputs are 1 and 2: if(input == 1) { //do processing ... } else { //do processing ... } |
在这种情况下,使用else将允许处理除1以外的所有值,而只应处理值1和2。
说其他的被认为是有害的,有点像说变量或类是有害的。见鬼,这甚至像是说goto是有害的。当然,事情可能会被误用。但在某些时候,你只需要相信程序员是成年人,并且足够聪明就可以了。
归根结底是这样的:如果你不愿意使用某个东西,因为某物上的答案或博客文章,甚至是Dijkstra的一篇著名论文告诉你不要这样做,你需要考虑编程是否是适合你的职业。
对我来说,某些流行语言结构本身就不好的整个概念是完全错误的。即使是
如果你写:
1 2 3 4 5 | if foo: # ... elif bar: # ... # ... |
那么读者可能会想:如果
1 2 3 4 5 6 | if foo: # ... else: # at this point, we know that bar is true. # ... # ... |
或:
1 2 3 4 5 6 | if foo: # ... else: assert bar # ... # ... |
这就向读者清楚地表明了您希望控制如何流动,而不需要读者对
(在最初的情况下,你仍然可以写一篇评论来解释正在发生的事情,但我想我会想:"为什么不直接使用
我认为重点不是你不应该使用
在编程语言中,大多数事情都是这样的,实际上是:—)
相反…在我看来,每一个国际单项体育联合会都必须有另外一个。当然,你可以做愚蠢的事情,但是如果你足够努力,你可以滥用任何构造。你知道"一个真正的程序员可以用每种语言编写Fortran"这句话。
我做的很多时间是写另一部分作为评论,描述为什么没有什么可以做。
在记录关于代码的假设时,else最有用。它确保您已经考虑了if语句的两边。
在"代码完成"中,总是在每个if语句中使用else子句甚至是推荐的做法。
首先,在python中包含
1 2 3 4 5 | try: something_that_might_raise_error() do_this_only_if_that_was_ok() except ValueError: # whatever |
问题是,如果
1 2 3 4 5 6 | try: something_that_might_raise_error() except ValueError: # whatever else: do_this_only_if_that_was_ok() |
我想在某种程度上这是一个意见问题,但我个人认为这是一个好主意,尽管我很少使用它。当我使用它时,感觉非常合适(而且,我认为它有助于澄清代码流)
在C族语言中存在一个所谓的"悬空-其他"问题,如下所示:
1 2 3 4 5 | if (a==4) if (b==2) printf("here!"); else printf("which one"); |
这种无辜的代码可以通过两种方式理解:
1 2 3 4 5 | if (a==4) if (b==2) printf("here!"); else printf("which one"); |
或
1 2 3 4 5 | if (a==4) if (b==2) printf("here!"); else printf("which one"); |
问题是"另一个"是"悬空的",人们可能会混淆另一个的所有者。当然,编纂者不会造成这种混乱,但对凡人是有效的。
多亏了python,我们在python中不能有其他悬而未决的问题,因为我们也必须编写
1 2 3 4 5 | if a==4: if b==2: print"here!" else: print"which one" |
或
1 2 3 4 5 | if a==4: if b==2: print"here!" else: print"which one" |
这样人类的眼睛就能捕捉到它。而且,不,我不认为"其他"是有害的,它和"如果"一样有害。
在我看来,对于任何语言和任何有默认方案或副作用的流控制语句,该方案都需要具有相同的考虑级别。if或switch或while中的逻辑仅与if(x)while(x)或for(…)中的条件相同。因此,该语句并不有害,但其条件中的逻辑是。
因此,作为开发人员,我们有责任在编写代码时考虑到其他的广泛范围。太多的开发人员将其视为"如果不是上面的话",而实际上它可以忽略所有常识,因为其中唯一的逻辑是对前面的逻辑的否定,这通常是不完整的。(算法设计错误本身)
然后,我不会认为"else"比for()循环或糟糕的内存管理中的"off"更有害。这都是关于算法的。如果您的自动机在其作用域和可能的分支中是完整的,并且所有这些都是具体的和理解的,那么就没有危险。危险在于人们没有意识到宽范围逻辑的影响而滥用表达式背后的逻辑。计算机是愚蠢的,他们做操作员告诉他们的事情(理论上)
我确实认为尝试和捕获是危险的,因为它会否定对未知数量的代码的处理。提升上方的分支可能包含一个bug,由提升本身突出显示。这是不明显的。这就像将一组连续的指令转换成一个错误处理树或图,其中每个组件都依赖于父级中的分支。奇怪的。注意,我爱C。
我认为关于
考虑:
1 2 3 4 5 6 7 8 | try: file = open('somefile','r') except IOError: logger.error("File not found!") else: # Some file operations file.close() # Some code that no longer explicitly references 'file' |
如果说上面的块阻止了代码试图访问不存在的文件或用户没有权限的目录,并且说所有内容都是封装的,因为它在一个
1 2 3 4 5 6 7 8 | try: file = open('somefile','r') except IOError: logger.error("File not found!") return False # Some file operations file.close() # Some code that no longer explicitly references 'file' |
你经常自欺欺人地说,因为
这就是我如何区分
在这个被假定为难以推理的例子中,它可以被明确地写出来,但是其他的仍然是必要的。例如。
1 2 3 4 5 6 7 | if a < 10: # condition stated explicitly elif a > 10 and b < 10: # condition confusing but at least explicit else: # Exactly what is true here? # Can be hard to reason out what condition is true |
可以写
1 2 3 4 5 6 7 8 | if a < 10: # condition stated explicitly elif a > 10 and b < 10: # condition confusing but at least explicit elif a > 10 and b >=10: # else condition else: # Handle edge case with error? |