在Python中的while循环条件中分配变量?

99

我刚刚看到了这段代码

while 1:
    line = data.readline()
    if not line:
        break
    #...

而且我认为,除了使用带有 break 的无限循环之外,一定还有更好的方法来处理这个问题。

所以我尝试了以下方法:

while line = data.readline():
    #...

而且,显然,出现了一个错误。

在那种情况下有没有避免使用break的方法?

编辑:

理想情况下,您应该避免两次使用readline... 在我看来,重复甚至比仅使用break更糟,特别是如果语句很复杂。


3
虽然这是一个很好的问题,我认为 for line in data 的解决方案非常适合这个具体的问题,但我不认为使用 while True: ... break 这种方法有什么问题。不要害怕它。 :-) - Kirk Strauser
4
这些答案提供了在while循环的条件语句中替代赋值的方法,但并没有回答这个问题:是否有一种方法在while循环中进行赋值?我遇到了同样的问题,试图执行while (character = string[i]) :我 知道 for循环是迭代字符串更好的方法,但我的条件语句实际上比这更复杂,我想将此赋值作为条件语句中“或”运算符的右侧。 - user2760926
1
@KirkStrauser,使用break语句的问题在于它需要四行代码来表达其他语言只需一行就能完成的操作。但是它确实做了正确的事情。到目前为止,没有任何答案提供了更好的通用解决方案。它们要么只适用于迭代器,要么复制赋值,这比使用break语句多三行代码还要糟糕。 - kasperd
11个回答

135

Python 3.8 开始,引入了 赋值表达式 (PEP 572) (:= 运算符),现在可以将 while 循环的条件值 (data.readline()) 捕获为变量 (line),以便在循环体内重复使用:

while line := data.readline():
  do_smthg(line)

3
顺便提一下,明确的条件可以写成 while (line := data.readline()) is not None: - Hi-Angel

44

尝试这个方法,适用于使用open('filename')打开的文件

for line in iter(data.readline, b''):

3
好的,我会尽力为你翻译。以下是需要翻译的内容:+1 for being exemplified in the python core documentation: https://docs.python.org/2/library/functions.html#iter - ThorSummoner

30
如果你没有进行任何更复杂的数据处理,比如接下来读取更多行,那么可以使用以下方法:

如果您不需要对数据进行更高级的操作,例如在之后读取更多的行,则可以使用以下方法:

for line in data:
    ... do stuff ...

我试图玩“难倒寿司爱好者”的游戏,思考一种可能支持.readline()但不支持__iter__()的对象类型data。我想不出来了。你有没有什么想法? - Kirk Strauser
这难道不需要先将整个文件读入内存吗?对于大文件来说似乎不适用。(特别是如果文件比你的内存还要大!) - ThorSummoner
如果data是一个文件对象(这个名字有点奇怪,但这是OP使用的方式),那么整个文件不会被读入内存。for line in data将迭代行,根据需要逐行读取它们。 - Ned Batchelder
根据https://docs.python.org/2/library/stdtypes.html#file.next的文档和我的不幸经历,文件指针并不在你期望的位置(例如对于`data.tell()`),而是在`for line in data`中甚至可能在最后一行被读取之前就已经到达文件末尾。因此,如果您依赖Python / OS来计算文件中的位置,则无法完全“按需读取”。 - mpag
1
@mpag 我绝对没有保证(也不是我想暗示有保证)每一行都会被精确读取。我是在反驳整个文件将被读入内存的观点。如果你按行迭代,就不能做出任何关于文件指针位置的假设。 - Ned Batchelder
这对于Python 3仍然适用吗? - winni2k

20

这并不是更好的方法,但这是我通常使用的方式。Python不像其他语言(比如Java)在变量赋值时返回其值。

line = data.readline()
while line:
    # ... do stuff ... 
    line = data.readline()

6
我不是那个的超级粉丝,特别是如果“...做一些事情...”是相当大的,因为它需要你谨记整个循环的流程,而你在进行 hack 时可能会出现问题。例如,如果你稍后添加了像 if line.startswith('foo'): continue 这样的代码,但没有意识到 line 只在最后更新,那么你就会意外地创建一个无限循环。 - Kirk Strauser
1
@Kirk - 在某种程度上,我同意,但其他选择也不是很好。理想情况下,你使用的类实现了一个生成器,你可以直接使用for循环,但在某些情况下,你需要使用while循环(例如,“while cur_time>expected_time:”)。我不知道OP的帖子是否更好,但我认为这是一个观点问题 :) - dfb
一个经典的while循环,对于任何水平的程序员都易于理解。可能是未来维护的最佳选择。 - Kim
1
@Kirk Strauser 有人可能会认为,如果“...做一些事情...”这么长,你已经迷失在循环中,那么你可能做错了。 - arkan

7

比如说,

for line in data:
    # ...

? 这很大程度上取决于 data 对象的 readline 语义。如果 data 是一个 file 对象,那么可以这样做。


5
for line in data:
    ... process line somehow....

使用for循环遍历文件中的每一行,而不是使用while循环。在我的经验中,这是读取文件的更常见的习惯用法(在Python中)。

实际上,data不必是一个文件,只需要提供一个迭代器即可。


5

从 Python 3.8 开始(该版本实现了 PEP-572),以下代码现在是有效的:

while line := data.readline():
   # do something with line 

3
如果data是一个文件,那么使用for line in file就可以正常工作,如其他答案所述。如果data不是一个文件,而是随机数据读取对象,则应将其实现为迭代器,实现__iter__next方法。 next方法应该进行读取,检查是否还有更多数据,如果没有,就引发StopIteration异常。如果这样做,您可以继续使用for line in data的习惯用法。

3
根据Python文档中的FAQ,使用for循环迭代输入或者运行无限循环while True并使用break语句来终止它,是首选和惯用的迭代方式。

2
您可以做以下事情:

line = 1
while line:
    line = data.readline()

7
这将导致循环体执行的次数比预期多一次。 - kasperd

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