while True与while {condition}的区别

3

我正在阅读比尔·卢巴诺维克(Bill Lubanovic)的《Python3入门》一书,遇到了一些我不确定是Python偏好还是只是为了描述其他东西而“简化”的内容。

它是关于如何使用块而不是一次性写入文件的说明。

poem = '''There was a young lady named Bright,
Whose speed was far faster than light;
She started one day
In a relative way,
And returned on the previous night.'''

fout = open('relativity', 'wt')
size = len(poem)
offset = 0
chunk = 100
while True:
    if offset > size:
        break
    fout.write(poem[offset:offset+chunk])
    offset += chunk
fout.close()

我本来想问为什么它使用while True而不是while (offset > size),但我决定自己尝试一下,并发现在我的Python控制台中while (offset > size)实际上没有做任何事情。
这只是控制台中的一个bug,还是Python真的要求你将条件放入while循环内部?通过尽可能简化所有更改,这似乎非常冗长。
(我来自Java、C#和JavaScript背景,在这些语言中,将条件作为循环定义是标准的。)
编辑
由于xnx的评论,我意识到我对条件的逻辑不正确。
这使我回到了一个更清晰的问题,即Python是否喜欢使用while True并在循环内部使用break来使用条件,还是作者在尝试解释不同的概念时犯了错误?

11
逻辑上的等价应该是 while offset <= size,是吗? - xnx
谢谢,我写这篇文章是因为意识到它应该在这里发布,而不是在我最初打算发布的代码审查网站上。然后我发现我认为可行的方法实际上并不可行,因此不适合那个网站。已经进行了编辑! - krillgar
1
while (offset > size) 这段代码没有任何效果,因为 offset 最初并不大于 size。 因此,该循环永远不会执行。 - user2555451
1
为什么这样写只是风格问题,我认为。(部分原因可能与“while True”在文件读取中很常见有关) - nneonneo
只是普通的文件读取 I/O(文件 I?)。同时恭喜你获得了披萨帽子 :) - nneonneo
显示剩余3条评论
6个回答

2
我本来想问为什么它使用while True而不是while (offset <= size),但我决定自己尝试一下。实际上,这就是我会写的方式。它在逻辑上应该是等价的。
我看到在我的Python控制台中,当(offset > size)时,while (offset > size)实际上并没有做任何事情。你需要使用(offset <= size)而不是(offset > size)。当前的逻辑是一旦offset大于size就停止,所以如果要将其放入while语句中,则需要反转条件。
Python确实要求你像那样将条件移到while循环内部吗?不,Python允许你直接在while循环中编写条件。两种选项都可以,这更多地是关于个人喜好如何编写逻辑。我更喜欢你建议的简单形式,而不是原作者的版本。
这应该可以正常工作:
while offset <= size:
    fout.write(poem[offset:offset+chunk])
    offset += chunk

有关详细信息,请参阅while文档,该文档明确指出任何表达式都可以在:之前使用。
编辑:

Python是否更喜欢使用while True:,并在循环内使用break来使用条件,还是作者在尝试解释不同概念时犯了一个错误?

Python不偏爱while True:。两种版本都可以,完全取决于编码者的个人喜好。我个人更喜欢将表达式保留在while语句中,因为我发现使用while offset <= size:使代码更清晰、简洁和易于维护。

1
这是合法的Python代码,可以在循环中放置条件。个人认为:
while offset <= size:

is clearer than:

while True:
    if offset < size:
        break

我更喜欢第一种形式,因为有一个较少的分支需要跟踪,但逻辑并不复杂。其他所有条件相等的情况下,缩进水平越低,阅读起来就越容易。 如果有多个不同的条件会打破循环,那么使用while True语法可能更可取。
至于错误循环逻辑的观察行为,请考虑以下代码片段:
size = len(poem)
offset = 0

while offset > size:
    #loop code

while循环永远不会被执行,因为offset > size一开始就是false。

谢谢。那是我的语法错误。请看到重新澄清的问题,现在已经发现了这个小错误。我的初衷是风格上的问题,而不是“为什么我的错误逻辑不起作用”。 - krillgar

1
while True:
    if offset > size:
        break
    func(x)

等价于


while offset <= size:
    func(x)

他们两个都运行,直到偏移量大于大小。这只是一种不同的措辞方式——两者都可以接受,我不知道是否有性能差异。只有当您在while循环底部(即在func(x)之后)具有中断条件时,它们才会以不同的方式运行。
编辑:
根据Python wiki,在Python 2.*中将条件放在while循环内会“大大减慢速度”:“这是由于首先测试while的True条件,然后再次测试”中断条件。我不知道他们对“很多”的衡量标准是什么,但它似乎足够微小。

2
Python维基百科的条目是错误的。你不能重新分配True,就像你不能重新分配1一样,而且dis显示没有值查找True - Adam Smith
@AdamSmith 啊!我错过了一个关键细节:“虽然在Python 2.*中”,也许这解决了你的问题? - Razi Shaban
2
天啊,你可以在Python2中重新分配“True”。这是谁的主意?! - Adam Smith
1
@AdamSmith:我认为这不是计划中的理想特性,而只是实现细节的意外。Python 2保持了关键字数量的控制。即使在Python3中,您仍然可以重新分配大多数Python2内置函数(如anyopenstr...),但True已从内置函数更改为关键字。 - Steve Jessop
@AdamSmith:Python并不总是有布尔类型。我相信他们不想破坏那些将True = 1赋值的代码,所以他们将其作为内置变量而不是关键字。 - user2357112

1

Python不偏好使用while True并在循环内使用break的条件,这是作者自己的怪癖或错误。

有些情况下,典型的Python风格(以及Guido van Rossum)会积极建议使用while True,但这不是这种情况。尽管如此,他们也没有反对它。我想可能有些情况下,“说何时停止”这样的测试比“说何时继续”更容易阅读和理解。即使它们只是逻辑上的否定,其中一个可能会更简单地表达事物:

while not god_unwilling() and not creek_risen():
while not (god_unwilling() or creek_risen()):

vs.

while True:
    if god_unwilling() or creek_risen():
        break

我仍然有点偏爱第一个,但可能因人而异。更好的做法是引入与英语习语相对应的函数:god_willing()creek_dont_rise() “必要”的使用情况是当您想在循环结束或中间执行中断测试时(也就是说,当您想在第一次无条件地执行部分或全部循环时)。其他语言具有更多种类的更复杂的循环结构,其他示例则使用变量玩游戏来决定是否中断,Guido建议“只需使用while True”。以下是FAQ中的一个示例,用于从赋值开始的循环
C代码:
while (line = readline(f)) {
    // do something with line
}

Python 代码:

while True:
    line = f.readline()
    if not line:
        break
    # do something with line

常见问题解答(与典型的Python风格有关):

有趣的现象是,大多数经验丰富的Python程序员都认识 while True 惯用语,并且似乎不太需要在表达式构造中添加赋值;只有新手才会强烈要求将其添加到语言中。

它还指出,对于这个特定的示例,实际上你可以通过使用 for line in f 来避免整个问题。


1
当从文件中读取时,通常会执行以下操作:

读取文本

output = []
while True:
    chunk = f.read(chunksize)
    if len(chunk) == 0:
        break
    output.append(chunk)

我觉得作者更习惯于阅读而不是写作,因此在编写代码时使用了读取习语while True
正如大多数回答问题的人所证明的那样,仅使用while offset <= size可能更具Pythonic和简单性,但更简单的可能只是这样做。
f.write(poem)

由于底层的I/O库可以为您处理分块写入,因此您无需担心。

在这样一个小的写入中,我同意只调用f.write(poem)。但如果你正在写一个巨大的文件,它是否仍然会内部分块处理呢? - krillgar

-2
在我看来,在大型程序中,while True 比其他方法更好;因为你实际上无法看到变量可能因某些函数等而改变。while True 意味着 如果是真的就开始,这意味着 开始这个循环,无论发生什么,除非关闭程序。因此,也许书的作者希望你使用 while True,比其他方法风险略小。
最好使用 while True 并定义可以停止此循环的变量。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接