为什么 python 在 for 和 while 循环后使用“else”?

2024-11-21 08:33:00
admin
原创
4
摘要:问题描述:我理解这个结构是如何工作的:for i in range(10): print(i) if i == 9: print("Too big - I'm giving up!") break else: print("...

问题描述:

我理解这个结构是如何工作的:

for i in range(10):
    print(i)

    if i == 9:
        print("Too big - I'm giving up!")
        break
else:
    print("Completed successfully")

但我不明白为什么else这里使用 关键字,因为它表明只有在for块未完成时才会运行相关代码,这与它所做的相反!无论我怎么想,我的大脑都无法无缝地从语句过渡forelse块。对我来说,continuecontinuewith更有意义(我正在尝试训练自己这样阅读它)。

我想知道 Python 程序员如何在脑海中(或者大声朗读,如果你愿意的话)读懂这个结构。也许我遗漏了某些可以让此类代码块更易于解读的东西?


这个问题是关于底层设计决策的,即为什么能够编写此代码很有用。有关语法含义的具体问题,另请参阅Python while 语句中的 Else 子句。


解决方案 1:

一种常见的构造是运行循环直到找到某些东西,然后跳出循环。问题是,如果我跳出循环或循环结束,我需要确定发生了哪种情况。一种方法是创建一个标志或存储变量,让我进行第二次测试以查看循环是如何退出的。

例如,假设我需要搜索一个列表并处理每个项目,直到找到一个标志项目,然后停止处理。如果缺少标志项目,则需要引发异常。

使用 Python for...else构造你有

for i in mylist:
    if i == theflag:
        break
    process(i)
else:
    raise ValueError("List argument missing terminal flag.")

将其与不使用此语法糖的方法进行比较:

flagfound = False
for i in mylist:
    if i == theflag:
        flagfound = True
        break
    process(i)

if not flagfound:
    raise ValueError("List argument missing terminal flag.")

在第一种情况下,它raise与它所使用的 for 循环紧密绑定。在第二种情况下,绑定不那么牢固,维护期间可能会引入错误。

解决方案 2:

即使对于经验丰富的 Python 程序员来说,这也是一个奇怪的构造。当与 for 循环结合使用时,它基本上意味着“在可迭代对象中找到某个项,否则如果没有找到则执行...”。例如:

found_obj = None
for obj in objects:
    if obj.key == search_key:
        found_obj = obj
        break
else:
    print('No object found.')

但是,无论何时看到这种构造,更好的选择是将搜索封装在一个函数中:

def find_obj(search_key):
    for obj in objects:
        if obj.key == search_key:
            return obj

或者使用列表推导:

matching_objs = [o for o in objects if o.key == search_key]
if matching_objs:
    print('Found {}'.format(matching_objs[0]))
else:
    print('No object found.')

它在语义上与其他两个版本并不等同,但在非性能关键代码中效果很好,无论是否迭代整个列表都无关紧要。其他人可能不同意,但我个人会避免在生产代码中使用 for-else 或 while-else 块。

另请参阅[Python-ideas] for...else 线程总结

解决方案 3:

Raymond Hettinger 有一篇精彩的演讲,题为《将代码转换为美观、惯用的 Python》,其中他简要介绍了该for ... else构造的历史。相关部分是“区分循环中的多个出口点” ,从 15:50 开始,持续约三分钟。以下是精彩内容:

  • for ... else结构由 Donald Knuth 设计,作为某些GOTO用例的替代品;

  • 重复使用else关键字是有意义的,因为“这是 Knuth 所使用的,并且人们知道,当时,所有 [for语句 ] 都在下面嵌入了一个ifand GOTO,并且他们期待else;”

  • 事后看来,它应该被称为“no break”(或可能是“nobreak”),这样就不会造成混淆。*

因此,如果问题是“他们为什么不改变这个关键字?”那么Cat Plus Plus 可能给出了最准确的答案——目前,它对现有代码的破坏性太大,不切实际。但如果你真正想问的问题是为什么else一开始就被重复使用,那么,显然当时这似乎是个好主意。

就我个人而言,我喜欢在可能乍一看会误认为属于循环内部的地方使用# no break内联注释的折衷方法else。这种方法相当清晰简洁。Bjorn 在其答案末尾链接的摘要中简要提到了此选项:

为了完整起见,我应该提到,只要对语法进行轻微的改变,想要这种语法的程序员现在就可以拥有它:

for item in sequence:
    process(item)
else:  # no break
    suite

  • 视频该部分的额外引言:“就像我们调用 lambda makefunction 时,没有人会问,‘lambda 做了什么?’”

解决方案 4:

为了简单起见,你可以这样想;

  • break如果在循环中遇到该命令forelse则不会调用该部分。

  • break如果在循环中没有遇到该命令forelse则会调用该部分。

换句话说,如果 for 循环迭代没有被“中断” break,那么该else部分就会被调用。

解决方案 5:

因为他们不想在语言中引入新的关键字。每个关键字都会窃取标识符并导致向后兼容性问题,所以这通常是最后的手段。

解决方案 6:

我发现,要“了解” for/else 的作用,以及更重要的是何时使用它,最简单的方法是专注于 break 语句跳转到的位置。For/else 构造是一个单独的块。break 跳出该块,因此跳过了 else 子句。如果 else 子句的内容只是跟在 for 子句后面,则永远不会被跳过,因此必须通过将其放在 if 中来提供等效逻辑。这之前已经说过,但不是完全用这些话,所以它可能对其他人有帮助。尝试运行以下代码片段。为了清晰起见,我完全赞成使用“no break”注释。

for a in range(3):
    print(a)
    if a==4: # change value to force break or not
        break
else: #no break  +10 for whoever thought of this decoration
    print('for completed OK')

print('statement after for loop')

编辑-我注意到这个问题仍在继续

第二个更好的想法......

“不中断”评论是负面的。理解正面断言要容易得多,那就是for可迭代对象已经耗尽。

for a in range(3):
    print(a)
    if a==4: # change value to force break or not
        print('ending for loop with a break')
        break
else: # when iterable exhausted  
    print('ending for loop as iterable exhausted')

print('for loop ended one way or another')

这也强化了这种解释

if iterable_supplies_a_value:
    run_the_for_with_that_value
else:
    do_something_else

解决方案 7:

我认为文档对else有很好的解释 ,继续

[...] 它是在循环因耗尽列表而终止时(使用 for)或当条件变为假时(使用 while)执行的,但不是在循环被 break 语句终止时执行的。

来源:Python 2 文档:控制流教程

解决方案 8:

由于技术部分已经基本得到解答,我的评论只是与产生这个回收关键字的混淆有关。

Python 是一种非常流畅的编程语言,但关键字的误用却更为臭名昭著。该else关键字完美地描述了决策树流程的一部分,“如果你不能这样做,(否则)就那样做”。这在我们自己的语言中是隐含的

相反,将此关键字与whileandfor语句一起使用会造成混淆。原因是,我们作为程序员的职业生涯告诉我们,语句else位于决策树中;它的逻辑范围,一个有条件地返回要遵循的路径的包装器。同时,循环语句有一个比喻性的明确目标来达到某个目标。该目标在流程的连续迭代后得以实现。

if / else 指示要遵循的路径。循环遵循路径,直到“目标”完成

问题是,else这个单词明确定义了条件中的最后一个选项。该单词的语义在 Python 和人类语言中都是相同的。但是人类语言中的 else 单词从不用于表示某人或某事在某事完成后将采取的行动。如果在完成过程中出现问题(更像是break语句),则会使用它。

最后,关键字将保留在 Python 中。很明显,这是一个错误,当每个程序员都试图想出一个故事来理解它的用法(就像某种助记符一样)时,情况会更加清楚。如果他们选择关键字,我会很高兴then。我相信这个关键字非常适合迭代流程,即循环后的回报。

这类似于一些孩子在按照每个步骤组装玩具后遇到的情形:然后爸爸呢

解决方案 9:

好的答案是:

  • 这解释了历史,

  • 这提供了正确的引用以简化您的翻译/理解。

我在这里的注释来自 Donald Knuth 曾经说过的(抱歉找不到参考资料),有一个结构其中 while-else 与 if-else 是无法区分的,即(在 Python 中):

x = 2
while x > 3:
    print("foo")
    break
else:
    print("boo")

具有与以下相同的流量(不包括低水平差异):

x = 2
if x > 3:
    print("foo")
else:
    print("boo")

重点是,if-else 可以看作是 while-else 的语法糖,后者break在块的末尾有 implicit if。相反的含义是,while循环是 的扩展if,这更常见(它只是重复/循环的条件检查),因为if通常在 之前教授while。然而,事实并非如此,因为这意味着每次else当条件为假时,while-else 中的块都会被执行。

为了便于你理解,可以这样想:

如果没有breakreturn等,循环仅在条件不再为真时结束,在这种情况下else块也将执行一次。对于 Python,for您必须考虑 C 样式for循环(带条件)或将其转换为while

另请注意:

循环内部过早的breakreturn等等使得条件不可能变为假,因为当条件为真时执行会跳出循环,并且永远不会回来再次检查它。

解决方案 10:

我读到的内容是这样的:

如果仍然满足运行循环的条件,则执行操作,否则执行其他操作。

解决方案 11:

我想知道 Python 程序员如何在脑海中读出这个结构(或者如果你愿意的话,大声读出来)。

我只是在心里想:

“否则没有break遇到……”

就是这样!

这是因为else仅当循环break中未遇到语句时才会执行该子句for

参考:

请参阅此处: https: //book.pythontips.com/en/latest/for_-_else.html#else-clause(添加了强调,并将“not”更改为“NOT”):

for循环还有一个else我们大多数人都不熟悉的子句。else子句在循环正常完成后执行。这意味着循环没有遇到 break 语句。


话虽如此,我建议不要使用该语言的这个不寻常的功能。不要else在 for 循环后使用该子句。它会让大多数人感到困惑,并且会降低他们阅读和理解代码的能力。

解决方案 12:

这里的关键词else可能会令人困惑,正如许多人指出的那样,像 这样的关键词nobreak更为notbreak合适。

为了从for ... else ...逻辑上理解,将其与 进行比较try...except...else,而不是if...else...,大多数python程序员都熟悉以下代码:

try:
    do_something()
except:
    print("Error happened.") # The try block threw an exception
else:
    print("Everything is find.") # The try block does things just find.

类似地,把 想象break成一种特殊的Exception

for x in iterable:
    do_something(x)
except break:
    pass # Implied by Python's loop semantics
else:
    print('no break encountered')  # No break statement was encountered

这个区别是python隐含的except break,你无法写出来,所以它变成:

for x in iterable:
    do_something(x)
else:
    print('no break encountered')  # No break statement was encountered

是的,我知道这种比较可能很困难而且令人厌烦,但它确实澄清了混淆。

解决方案 13:

我读到的是“当iterable完全耗尽,并且执行即将在 完成后继续执行下一个语句时for,将执行 else 子句。”因此,当迭代被 中断时break,这将不会被执行。

解决方案 14:

我同意,它更像是“elif not [条件引发中断]”。

我知道这是一个老话题,但我现在正在研究同样的问题,而且我不确定是否有人按照我理解的方式找到了这个问题的答案。

对我来说,有三种“读取” elseinFor... elseWhile... else语句的方法,它们都是等效的,分别是:

  1. else == if the loop completes normally (without a break or error)

  2. else == if the loop does not encounter a break

  3. else == else not (condition raising break)(假设存在这样的情况,否则你不会有循环)

因此,本质上,循环中的“else”实际上是“elif ...”,其中‘...’表示 (1) 无中断,相当于 (2) 非 [引发中断的条件]。

我认为关键是如果else没有“中断”,那么就没有意义,因此for...else包括:

for:
    do stuff
    conditional break # implied by else
else not break:
    do more stuff

因此,循环的基本元素for...else如下,您可以用更简单的英语阅读它们:

for:
    do stuff
    condition:
        break
else: # read as "else not break" or "else not condition"
    do more stuff

正如其他海报所说,当您能够找到循环所寻找的内容时,通常会引发中断,因此就else:变成了“如果找不到目标项该怎么办”。

例子

您还可以同时使用异常处理、中断和 for 循环。

for x in range(0,3):
    print("x: {}".format(x))
    if x == 2:
        try:
            raise AssertionError("ASSERTION ERROR: x is {}".format(x))
        except:
            print(AssertionError("ASSERTION ERROR: x is {}".format(x)))
            break
else:
    print("X loop complete without error")

结果

x: 0
x: 1
x: 2
ASSERTION ERROR: x is 2
----------
# loop not completed (hit break), so else didn't run

例子

发生中断的简单示例。

for y in range(0,3):
    print("y: {}".format(y))
    if y == 2: # will be executed
        print("BREAK: y is {}
----------".format(y))
        break
else: # not executed because break is hit
    print("y_loop completed without break----------
")

结果

y: 0
y: 1
y: 2
BREAK: y is 2
----------
# loop not completed (hit break), so else didn't run

例子

简单的例子,没有中断,没有引发中断的条件,也没有遇到错误。

for z in range(0,3):
     print("z: {}".format(z))
     if z == 4: # will not be executed
         print("BREAK: z is {}
".format(y))
         break
     if z == 4: # will not be executed
         raise AssertionError("ASSERTION ERROR: x is {}".format(x))
else:
     print("z_loop complete without break or error
----------
")

结果

z: 0
z: 1
z: 2
z_loop complete without break or error
----------

解决方案 15:

当循环没有被打破时,语句块内的代码else都会被执行。for

for x in xrange(1,5):
    if x == 5:
        print 'find 5'
        break
else:
    print 'can not find 5!'
#can not find 5!

来自文档:break 和 continue 语句,以及循环中的 else 子句

循环语句可以有一个 else 子句;当循环因耗尽列表而终止(使用 for)或条件变为 false(使用 while)时,它会被执行,但当循环被 break 语句终止时不会执行。以下循环就是一个例子,它搜索素数:

>>> for n in range(2, 10):
...     for x in range(2, n):
...         if n % x == 0:
...             print(n, 'equals', x, '*', n//x)
...             break
...     else:
...         # loop fell through without finding a factor
...         print(n, 'is a prime number')
...
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3

(是的,这是正确的代码。仔细看:else 子句属于 for 循环,而不是 if 语句。)

与循环一起使用时,else 子句与 try 语句的 else 子句的共同点多于与 if 语句的 else 子句的共同点:try 语句的 else 子句在未发生异常时运行,而循环的 else 子句在未发生 break 时运行。有关 try 语句和异常的更多信息,请参阅处理异常。

continue 语句也是从 C 语言中借用的,它继续循环的下一次迭代:

>>> for num in range(2, 10):
...     if num % 2 == 0:
...         print("Found an even number", num)
...         continue
...     print("Found a number", num)
Found an even number 2
Found a number 3
Found an even number 4
Found a number 5
Found an even number 6
Found a number 7
Found an even number 8
Found a number 9

解决方案 16:

这是我上面没有看到其他人提及的一种思考方式:

首先,请记住 for 循环基本上只是 while 循环的语法糖。例如,循环

for item in sequence:
    do_something(item)

可以(近似地)重写为

item = None
while sequence.hasnext():
    item = sequence.next()
    do_something(item)

其次,请记住,while 循环基本上只是重复的 if 块!您始终可以将 while 循环理解为“如果此条件为真,则执行主体,然后返回并再次检查”。

因此 while/else 非常有意义:它与 if/else 具有完全相同的结构,但增加了循环功能,直到条件变为假,而不仅仅是检查一次条件。

然后 for/else 也完全有意义:因为所有的 for 循环都只是 while 循环之上的语法糖,你只需要弄清楚底层 while 循环的隐式条件是什么,然后 else 就对应于该条件变为 False 的时候。

解决方案 17:

for i in range(3):
    print(i)

    if i == 2:
        print("Too big - I'm giving up!")
        break;
else:
    print("Completed successfully")

这里的“else”非常简单,只是意味着

1、“如果for clause完成”

for i in range(3):
    print(i)

    if i == 2:
        print("Too big - I'm giving up!")
        break;
if "for clause is completed":
    print("Completed successfully")

编写像“for 子句已完成”这样的长语句很困难,因此他们引入了“else”。

else就其本质而言,这是一个“如果”。

2,但是,for clause is not run at all

In [331]: for i in range(0):
     ...:     print(i)
     ...: 
     ...:     if i == 9:
     ...:         print("Too big - I'm giving up!")
     ...:         break
     ...: else:
     ...:     print("Completed successfully")
     ...:     
Completed successfully

所以它的完整陈述是逻辑组合:

if "for clause is completed" or "not run at all":
     do else stuff

或者这样说:

if "for clause is not partially run":
    do else stuff

或者这样:

if "for clause not encounter a break":
    do else stuff

解决方案 18:

除了搜索之外,这里还有另一个惯用的用例。假设您想要等待某个条件为真,例如远程服务器上的端口打开,以及一些超时。那么您可以使用while...else如下构造:

import socket
import time

sock = socket.socket()
timeout = time.time() + 15
while time.time() < timeout:
    if sock.connect_ex(('127.0.0.1', 80)) is 0:
        print('Port is open now!')
        break
    print('Still waiting...')
else:
    raise TimeoutError()

解决方案 19:

我只是想自己再理解一下。我发现以下内容很有帮助!

• 认为 是else与循环内的 配对if(而不是 与for) - 如果条件满足,则中断循环,否则执行此操作 - 除非它else与多个ifs 配对! • 如果根本

没有s 得到满足,则执行。
• 多个s 实际上也可以被认为是- s!if`else`
if`if`elif

解决方案 20:

else 子句在循环正常完成后执行。这意味着,
仅当循环未由 break 语句终止时,才会执行 for/while 之后的 :==> else 块

for item in lista:
if(obj == item ):
    print("if True then break will run and else not run")
    break;
else:
print("in  else => obj not fount ")

解决方案 21:

无论循环是否进入其主体,循环的 else 分支都会执行一次,除非进入了循环主体但未完成。也就是说,在循环内部遇到了 break 或 return 语句。

my_list = []
for i in my_list:
    print(i, end=',')
else:
    print('loop did not enter')

##################################    

for i in range(1,6,1):
    print(i, end=',')
else:
    print('loop completed successfully:', i)

##################################    

for i in range(1,6,1):
    if i == 3:
        print('loop did not finish:', i)
        break
    print(i, end=',')
else:
    print('else:', i)

输出:

loop did not enter
1,2,3,4,5,loop completed successfully: 5
1,2,loop did not finish: 3

while-else 也一样。

import random
random.seed(8)

i = 100
while i < 90:
    print(i, end=',')
    i = random.randint(0,100)
else:
    print('loop did not enter:', i)

##################################    

i = 25
while i < 90:
    print(i, end=',')
    i = random.randint(0,100)
else:
    print('loop completed successfully:', i)

##################################    

i = 25
while i < 90:
    if i % 10 == 0:
        print('loop did not finish:', i)
        break
    print(i, end=',')
    i = random.randint(0,100)
else:
    print('else:', i)

输出:

loop did not enter: 100
25,29,47,48,16,24,loop completed successfully: 90
25,5,loop did not finish: 10

解决方案 22:

对于程序员来说,这可能看起来令人困惑,因为我们总是期望在if面对时看到else,但在现实生活中我们else使用for

举个例子,我让我的儿子在书架上找一本字典并把它拿给我,如果他找不到,那么他就应该去给我买一本

这是algorithm心中his

for book in bookshelf:
    if book == 'dictionary':
        #Lucky Me !! I find it lets bring it to dad
        bring('dictionary')
        break #and of course I break and stop searching 
else: #too bad :( we do not have any dictionaries
    buy('dictionary');

解决方案 23:

for i in range(10):
    print(i)

    if i == 9:
        print("Too big - I'm giving up!")
        break;
else:
    print("Completed successfully")

break 关键字用于结束循环。如果 i = 9,则循环结束。当任何if条件不满足时,将else执行剩下的部分。

解决方案 24:

您可以将其想象
else成其余的东西,或者其他未在循环中完成的东西。

解决方案 25:

我认为该结构类似于 for (if) A else B,而 for(if)-else大致是一种特殊的 if-else。它可能有助于理解else

A和B最多执行一次,与if-else结构相同。

for(if) 可以看作是一种特殊的 if,它会进行循环以尝试满足 if 条件。一旦满足if条件,A 和break否则,B。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用