在answer中(S.Lott) 提出有关Python try...else
声明的问题:
实际上,即使在if语句中,也是如此 否则:可以在真正可怕的情况下被滥用 创建非常困难的错误的方法 找到。 [...]
三思而后行:它是 通常是一个问题。避免它除外 在一个if语句中,即便如此 考虑记录其他 - 条件使其明确。
这是一个广泛持有的观点吗?是else
considered harmful?
当然,您可以使用它编写令人困惑的代码,但对于任何其他语言构造都是如此。甚至Python的for...else
在我看来也是一件非常方便的事情(对try...else
来说不那么重要)。
答案 0 :(得分:30)
S.Lott显然已经看到了一些不好的代码。我们都不是吗?我不认为其他有害的,虽然我已经看到它曾用于编写错误的代码。在这些情况下,所有周围的代码也都很糟糕,所以为什么要责怪其他人?
答案 1 :(得分:15)
不,它没有害处,这是必要的。
总是应该有一个包罗万象的声明。所有开关都应该有一个默认值。 ML语言中的所有模式匹配都应该有默认值。
在一系列if语句之后不可能推断出真实情况的论点是生活中的事实。计算机是那里最大的有限状态机,在每种情况下列举每一种可能性都是愚蠢的。
如果您真的害怕在其他语句中忽略未知错误,那么在那里提出异常真的很难吗?
答案 2 :(得分:7)
说其他被认为是有害的有点像说变量或类是有害的。哎呀,甚至说goto是有害的。当然,事情可能会被滥用。但在某些时候,你只需要信任程序员成为成年人,并且要足够聪明,不要这样做。
归结为:如果你不愿意使用某些东西,因为SO或博客文章的答案,甚至Dijkstra的一篇着名论文告诉你不要,你需要考虑编程是否正确适合你。
答案 3 :(得分:7)
我不会说它有害,但有时候else语句会让你陷入困境。例如,如果您需要根据输入值进行一些处理,并且只有两个有效的输入值。只检查一个可能会引入一个错误。 例如:
The only valid inputs are 1 and 2:
if(input == 1)
{
//do processing
...
}
else
{
//do processing
...
}
在这种情况下,使用else将允许处理除1之外的所有值,只应该是值1和2。
答案 4 :(得分:6)
对我而言,某些流行语言结构本质上不好的整个概念是完全错误的。即使goto
也有它的位置。我见过使用它的Walter Bright和Linus Torvalds之类的非常易读,可维护的代码。只是教程序员可读性和使用常识而不是随意声明某些结构“有害”,这样做要好得多。
答案 5 :(得分:4)
如果你写:
if foo:
# ...
elif bar:
# ...
# ...
然后读者可能会疑惑:如果foo
和bar
都不是真的会怎么样?根据您对代码的理解,您可能知道必须是foo
或bar
的情况。我更愿意看到:
if foo:
# ...
else:
# at this point, we know that bar is true.
# ...
# ...
或:
if foo:
# ...
else:
assert bar
# ...
# ...
这使读者清楚地了解您希望控制如何流动,而无需读者仔细了解foo
和bar
的来源。
(在最初的情况下,你仍然可以写一条评论来解释发生了什么,但我想我会想:“为什么不只使用else:
条款?”)
我认为关键不在于你不应该使用else:
;相反, else:
条款可以让您编写不清楚的代码,您应该尝试识别何时发生这种情况,并添加一些评论来帮助任何读者。
对于编程语言中的大多数事情都是如此,实际上: - )
答案 6 :(得分:3)
其他在记录有关代码的假设时最有用。它确保您通过if语句的两个方面进行思考。
对于每个if语句,始终使用else子句甚至是“代码完成”中的推荐做法。
答案 7 :(得分:3)
Au contraire ...在我看来,每个if都必须有一个别的东西。当然,你可以做愚蠢的事情,但是如果你努力的话,你可以滥用任何构造。你知道这句话“一个真正的程序员可以用各种语言写FORTRAN”。
我做了很多时间是将其他部分写成评论,描述为什么没有什么可做的。
答案 8 :(得分:2)
首先在Python中包含else
语句(try...else
)背后的基本原理是仅捕获您真正想要的异常。通常当你有一个try...except
块时,会有一些代码可能引发异常,然后还有一些代码只能在前面的代码成功时运行。如果没有else
块,则必须将所有代码放在try
块中:
try:
something_that_might_raise_error()
do_this_only_if_that_was_ok()
except ValueError:
# whatever
问题是,如果do_this_only_if_that_was_ok()
提出ValueError
该怎么办?当你可能不想要它时,它会被except
语句捕获。这就是else
块的目的:
try:
something_that_might_raise_error()
except ValueError:
# whatever
else:
do_this_only_if_that_was_ok()
我想这在某种程度上是一个意见问题,但我个人认为这是一个好主意,即使我很少使用它。当我使用它时,它感觉非常合适(此外,我认为它有助于澄清代码流程)
答案 9 :(得分:1)
对我来说,对于任何语言和任何存在默认情景或副作用的流量控制语句,该情景需要具有相同的考虑水平。 if或switch或while中的逻辑与if(x)while(x)或for(...)的条件一样好。因此,该陈述无害,但其条件的逻辑是。
因此,作为开发人员,我们有责任在其他方面进行编码。太多开发人员将其视为“如果不是上述”,事实上它可以忽略所有常识,因为其中唯一的逻辑是对前面逻辑的否定,这通常是不完整的。 (算法设计错误本身)
我不认为'else'在for()循环或坏内存管理中比off-by-ones更有害。这都是关于算法的。如果你的自动机在其范围和可能的分支中是完整的,并且所有都是具体和理解的,则没有危险。危险是滥用人们没有意识到宽范围逻辑影响的表达背后的逻辑。 计算机是愚蠢的,他们按照运营商的说法行事(理论上)
我认为尝试和捕获是危险的,因为它可以取消对未知数量代码的处理。分支在加注之上可能包含错误,由加注本身突出显示。这可能是不明显的。这就像将一组连续的指令转换为错误处理的树或图,其中每个组件都依赖于父组中的分支。奇。请注意,我喜欢C。
答案 10 :(得分:1)
在C系列语言中遇到一个所谓的“悬空”问题,如下所示:
if (a==4)
if (b==2)
printf("here!");
else
printf("which one");
这种无辜的代码可以通过两种方式理解:
if (a==4)
if (b==2)
printf("here!");
else
printf("which one");
或
if (a==4)
if (b==2)
printf("here!");
else
printf("which one");
问题在于“其他”是“悬空”,人们可能会混淆其他人的主人。当然编译器不会产生这种混淆,但它对凡人有效。
感谢Python,我们不能在Python中遇到一个悬而未决的问题,因为我们必须编写
if a==4:
if b==2:
print "here!"
else:
print "which one"
或
if a==4:
if b==2:
print "here!"
else:
print "which one"
让人眼捕捉到它。并且,不,我不认为“其他”是有害的,它与“如果”一样有害。
答案 11 :(得分:0)
在一个很难推理的例子中,可以明确地写出来,但是其他的仍然是必要的。 例如。
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
可以写
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?
答案 12 :(得分:0)
我认为关于try...except...else
的观点是,使用它来创建不一致的状态而不是修复它是一个容易的错误。不应该不惜一切代价避免它,但它可能适得其反。
考虑:
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'
如果上述块阻止代码尝试访问不存在的文件或用户没有权限的目录,并且说所有内容都被封装,因为它在一个try...except...else
块。但实际上,上面表格中的很多代码应该是这样的:
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'
你经常愚弄自己,因为file
不再在范围内被引用,在块之后继续编码是可以的,但在许多情况下会出现一些不合适的地方。或者稍后可能会在else
块中创建一个未在except
块中创建的变量。
这就是我将if...else
与try...except...else
区分开的方式。在这两种情况下,必须在大多数情况下使块并行(变量和状态设置在一个中应该在另一个中设置),但在后者中,编码器通常不会,可能是因为它不可能或不相关。在这种情况下,返回呼叫者通常会比在最佳情况下尝试并继续解决您认为的情况更有意义。