【问题标题】:Assign variable in while loop condition in Python?在Python的while循环条件中分配变量?
【发布时间】:2011-10-01 15:32:41
【问题描述】:

我刚刚遇到了这段代码

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

并想,必须有更好的方法来做到这一点,而不是使用break 的无限循环。

所以我尝试了:

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

很明显,出现了错误。

有什么方法可以避免在这种情况下使用break

编辑:

理想情况下,您应该避免说两次readline...恕我直言,重复甚至比break 更糟糕,尤其是在语句很复杂的情况下。

【问题讨论】:

  • 虽然这是一个很好的问题,我认为for line in data 解决方案非常适合这个特定问题,但我认为while True: ... break 成语没有任何问题。不要害怕它。 :-)
  • 这些答案提供了在 while 循环的条件下赋值的替代方法,但实际上并没有回答这个问题:有没有办法在 while 循环中进行赋值?我遇到了同样的问题,试图做 while (character = string[i]): I know for-loop 是迭代字符串的更好方法,但我的条件是实际上比这复杂得多,我想将这个赋值作为条件中“或”的右侧。
  • @KirkStrauser break 结构的问题在于,它使用四行来表达某些东西,而其他语言只需一行就可以做到。然而,它做正确的事。到目前为止给出的答案都没有提供更好的通用解决方案。它们要么只使用迭代器,要么重复赋值,这比 break 版本的额外三行代码更糟糕。

标签: python while-loop variable-assignment


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    【解决方案3】:

    如果您没有对数据做任何花哨的事情,比如稍后阅读更多行,那么总会有:

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

    【讨论】:

    • 我试图通过考虑一种类型的对象data 来玩 Stump The Sushi Eater,它可能支持 .readline() 但不支持 __iter__()。我在画一个空白。你知道任何副手吗?
    • 这不需要先将整个文件读入内存吗?这似乎不适用于大文件。 (特别是如果文件比你的 ram 可以容纳的大!)
    • 如果 data 是一个文件对象(这是一个奇怪的名字,但这是 OP 使用它的方式),那么整个文件将不会被读入内存。 for line in data 将遍历行,根据需要读取它们。
    • @NedBatchelder:根据docs.python.org/2/library/stdtypes.html#file.next 的文档 - 以及我不幸的经历 - 文件指针不在您期望的位置(例如data.tell())和for line in data 和甚至在读取最后一行之前甚至可能位于文件末尾。因此,如果您指望 python/os 来计算您在文件中的位置,它并不能完全“根据需要读取它们”。
    • @mpag 绝对不能保证(我也不是暗示有)每一行都根据需要精确读取。我反对将整个文件读入内存的想法。如果按行进行迭代,则无法对文件指针的位置做出任何假设。
    【解决方案4】:

    这并没有好多少,但这是我通常这样做的方式。 Python 不会像其他语言(例如 Java)那样在变量赋值时返回值。

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

    【讨论】:

    • 我不是这个的忠实拥护者,特别是如果... do stuff ... 相当大,因为它要求你在修改它时牢记整个循环的流程。例如,如果您稍后添加 if line.startswith('foo'): continue 之类的内容而没有意识到 line 仅在最后更新,那么您不小心创建了一个无限循环。
    • @Kirk - 在某种程度上,我同意,但替代方案也好不到哪里去。理想情况下,你使用的类实现了一个生成器,你可以只使用一个 for 循环,但在某些情况下你需要一个 while 循环(例如,'while cur_time>expected_time:')。我不知道 OPs 的帖子是否更好,但我想这是一个见仁见智的问题 :)
    • 经典的while循环,任何水平的程序员都可以理解。可能是未来维护目的的最佳选择。
    • @Kirk Strauser 有人可能会争辩说,如果 ... do stuff ... 太长了,以至于您忘记了循环中发生的事情,那么您可能做错了。
    【解决方案5】:

    喜欢,

    for line in data:
        # ...
    

    ?它很大程度上取决于 data 对象的 readline 语义的语义。如果 data 是一个 file 对象,那将起作用。

    【讨论】:

      【解决方案6】:
      for line in data:
          ... process line somehow....
      

      将遍历file 中的每一行,而不是使用while。根据我的经验(在 Python 中),读取文件的任务是一个更常见的习语。

      事实上,data 不必是一个文件,而只是提供一个迭代器。

      【讨论】:

        【解决方案7】:

        从 python 3.8(实现 PEP-572)开始,此代码现在有效:

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

        【讨论】:

          【解决方案8】:

          如果data 有一个函数返回一个迭代器而不是readline(比如data.iterate),你可以这样做:

          for line in data.iterate():
              #...
          

          【讨论】:

          • 除非你知道 data 很小(甚至那时真的没有),否则不要这样做,因为 .readlines() 将整个内容吸入 RAM,但它并没有真正为你买任何东西返回。
          • 如果函数返回一个迭代器而不是整个列表,它应该可以正常工作,对吗?
          • 是的,但我还没有看到 .readlines() 以这种方式实现。 file.readlines() 的文档说它将“使用 readline() 读取直到 EOF 并返回一个包含如此读取的行的列表。”
          • 我更喜欢这个答案。 :-) 但是,iterate 的常用名称是__iter__,然后您可以将循环重写为for line in data
          • 是的,但我要这样说,因为已经有 4 个其他答案具有 for line in data。 =D
          【解决方案9】:

          如果data 是一个文件,如其他答案所述,使用for line in file 可以正常工作。如果 data 不是文件,并且是随机数据读取对象,那么您应该将其实现为迭代器,实现 __iter__next 方法。

          next 方法应该读取,检查是否有更多数据,如果没有,请提出StopIteration。如果这样做,您可以继续使用for line in data 成语。

          【讨论】:

            【解决方案10】:

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

            【讨论】:

              【解决方案11】:

              你可以这样做:

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

              【讨论】:

              • 这将比预期多执行一次循环体。
              猜你喜欢
              • 1970-01-01
              • 2013-04-07
              • 2015-11-04
              • 2013-11-15
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多