退出 for 循环
Posted
技术标签:
【中文标题】退出 for 循环【英文标题】:returning out of for-loop 【发布时间】:2011-01-22 17:52:58 【问题描述】:我是 python 的新手,我想知道这是不是:
def func(self, foo):
for foo in self.list:
if foo.boolfunc(): return True
return False
是很好的做法。
我可以像上面那样退出循环,还是应该像这样使用while循环?
def func(self, foo):
found = false
while(not found & i < len(self.list)):
found = foo.boolfunc()
++i
return found
我的 java 教授警告我们不要在循环中使用中断,但这在技术上不是中断,而且更简洁,所以......是的
谢谢
【问题讨论】:
您的替代版本不是很好的 Python。将and
用于逻辑与。避免使用&
,除非您正在执行按位操作。
你的 Java 教授错了。
你的 Java 教授让你思考这个问题是在帮你一个大忙。
foo是循环变量,为什么将foo传递给函数?
@codeape,我认为 foo 只是这个例子的占位符
【参考方案1】:
这是个好习惯。
我的 java 教授警告我们不要在循环中使用中断
这是为什么呢? “从不”是计算机科学中的一个强词,不应该(...)使用。1)
1) 除了“goto”……我们都有自己的烦恼。 ;-)
【讨论】:
谢谢!好吧,他说这是一个坏习惯,可以(几乎?)总是用更好的东西代替。 它几乎总是可以代替休息,是否更好是一个见仁见智的问题 @jk:总是可以将break
替换为退出条件。实际上有一个证明,它是“结构化编程证明理论中的控制流”。
@Konrad Rudolph:对于学习编程的学生来说,“永远”永远不够强大。对于学生来说,你总是必须使用绝对值,否则他们永远不会明白边缘条件真的是边缘条件。
@S.Lott:是的,我也使用它,即使在我不得不承认的有争议的话题上也是如此。但在这里教授是错(即不分享我的意见)。 ;-)【参考方案2】:
你的例子没有错,但最好写
def func(self, foo):
return any(foo.boolfunc() for foo in self.list)
【讨论】:
谢谢,我还不熟悉python的来龙去脉,但是像这样的东西让我想了解更多 any() 的文档:docs.python.org/library/functions.html#any。生成器表达式的文档:docs.python.org/tutorial/classes.html#generator-expressions【参考方案3】:您的教授提倡一种称为“单点返回”的做法,它基本上表明任何代码块都应该只有一个退出点。循环中的中断与此有些不同,但通常集中在一起。
这是一个有争议的观点,至少可以说,而且肯定不像“永远不要使用 goto”那样严格而快速的规则。以他的方式这样做可能是值得的 - 你可以安抚他,也可以看到这两种方法的好处,但大多数人可能对单点返回并不太严格,如果违反它会使他们的代码更具可读性。
【讨论】:
【参考方案4】:“跳出循环”很容易变成坏习惯,因为它隐藏了循环的终止条件。
如果您的 if
语句具有中等复杂性,则可能不清楚循环建立了什么后置条件。
如果您的退出条件明显,那么提前退出是一种常见的句法优化。
如果您的退出条件不明显,那么一组复杂的、嵌套的、难以理解的if
语句对您的弊大于利。
确实,this SO question 表明,一个简单的try
块的存在可能会导致令人困惑的情况,以至于生成了一段明显不正确的代码,并且不容易被调试。
通常,所有“提前退出”的事情(尤其是break
语句)都会导致创建正式证明的问题。 (else
语句也有类似的问题。)
如果您通过推理创建必要的后置条件所需的语句来开发程序,那么您将永远不需要break
或早期的return
,因为您无法使用正式方法轻松创建这些语句。
另外,请注意,任何避免 break
或 else
的建议都会导致仇恨邮件和投票。由于莫名其妙的原因,仔细研究一些编程结构是一件坏事。
"else" considered harmful in Python?
如果带有break
(或早期return
)的循环的退出条件不是明显,您需要重新设计以使其明显。
在本例中,它们是显而易见的,因此所呈现的具体示例没有问题。
【讨论】:
@S.Lott:您认为形式证明的相关性如何?根据我的经验,一点也不,因为即使是简单的算法也太复杂了,而且这种复杂性不会因为你是否使用提前退出而改变。事实上,循环不变量不会改变任何一种方式。 (不是我的反对票,顺便说一句。你的观点仍然很好。) @Konrad Rudolph:它们是必不可少的。在合理可用的语言中,“原语”——语句、内置数据类型等——将有证据证明这些东西确实像宣传的那样工作。有些证明非常正式,有些则比较正式。但是如果没有一定程度的信任,人们就会慢慢失去对这种语言的信心。 这种形式化的方法与编写大量代码的实用性直接不一致,这可能就是这种建议被否决的原因。任何曾经尝试跟踪使用 10 个标志而不是 10 个返回的复杂例程的任何人都会立即得到 -1 这样的建议。 说实话,我从来没有听说过,我很怀疑。当然,数学库将使用形式证明和其他一些东西。但除此之外……没有大的存在。事实上,如果“工作中的程序员”有任何迹象的话,很少有优秀的程序员会使用形式证明。 @romkyns:“实用性”不是问题。这个问题显然是正确的。如果你的代码很好,你不需要每一行的正式证明。如果你的代码很糟糕,正式的证明心理训练可以帮助减少错误。【参考方案5】:值得一提的是,在 Python 中,for loops can have an else clause。 else 子句仅在循环因列表耗尽而终止时执行。
所以你可以写:
def func(self):
for foo in self.list:
if foo.boolfunc():
return True
else:
return False
【讨论】:
【参考方案6】:“提前退出”是一种完美的 Pythonic 风格(当有保证时:gnibbler 的回答正确指出,对于您的特定用例,有一个内置的 [[in Python 2.5 and better]] 更可取)并且通常有助于实现 Pythonic “平面优于嵌套”的目标。而for
通常是在 Python 中进行循环的正确方法,在应用程序级别:如果有任何复杂的循环逻辑(可能需要while
),通常最好将其推送到辅助生成器。
有时声称替代“单点出口”的优势包括存在一个可以执行清理的“出口瓶颈”。但是,由于总是可能出现异常,您不知道您的单个 return
是一个独特的退出瓶颈,即使您有它:确保良好清理的正确方法是 @ 987654326@ 语句(在 2.6 或 2.5 中带有“从未来导入”;对于较旧版本的 Python,使用 try
/finally
代替旧版本,但仍然有用)。
Knuth 的文章“使用 Goto 语句进行结构化编程”(pdf)——这是一篇令人难以置信的、富有远见的文章,作者于 1974 年发表,被许多人认为是计算机科学的传奇人物,无论是理论还是实践——都值得一读。任何怀疑这篇文章对 Python 的适用性的人都应该考虑下面的简短引用:
类似缩进的设备,而不是 分隔符,可能变得可行 表示局部结构 源语言。
在 Python 1.0 发布 20 年前,Knuth已经预见到将成为 Python 标志的关键语法方面(以及,独立地,Haskell,比 Python 早一点发布——从与 Knuth、Peyton Jones 和 van Rossum 的个人讨论中,我可以证明他们都声称这三个“用于分组的缩进”的发明是完全独立的,只是“伟大的”的一个例子思想一致”——或者,用查尔斯·福特的话来说,“这只是蒸汽机时代”;-)。
代码的形式证明,包括提前退出,当然并不比具有单点退出的等效代码更难,因为 Corrado Böhm 和 Giuseppe Jacopini 的著名证明展示了如何从任何流程图执行机械转换到一个只包含序列、选择和重复的程序(但当然,转换后的程序——就像任何其他试图避免提前退出风格的程序一样——容易有比需要更多的嵌套,以及额外的布尔“状态”变量,这会影响可读性、直接性和效率——使早期退出在支持它的语言中更加优越)。
【讨论】:
@Konrad,很高兴你喜欢它!-)以上是关于退出 for 循环的主要内容,如果未能解决你的问题,请参考以下文章
六十九for循环while循环break跳出循环continue结束本次循环exit退出整