【问题标题】:Python Assign value to variable during condition in while LoopPython在while循环的条件下为变量赋值
【发布时间】:2013-11-15 01:57:32
【问题描述】:

一个关于 Python 语法的简单问题。我想在while循环的条件下将一个函数的值分配给一个变量。当函数返回的值为 false 时,循环应该中断。我知道如何在 PHP 中做到这一点。

while (($data = fgetcsv($fh, 1000, ",")) !== FALSE) 

但是,当我在 Python 中尝试类似的语法时,会出现语法错误。

【问题讨论】:

  • 如果您在 Python 中有一个函数 fgetcsv,它返回一个字符串或 False,因此与您在 PHP 中的模式完全相同,那么 for data in iter(lambda: fgetcsv(fh, 1000, ","), False): 将产生您想要的效果。
  • @Duncan - 嗯...如果您想要一个更通用的 iter 并将任何 Falsey 值视为哨兵怎么办?
  • 我更新了 2020 年的答案; := 运算符从 Python 3.8 开始存在。

标签: python while-loop variable-assignment


【解决方案1】:

2020 年答案:

从 Python 3.8 开始,"walrus operator" := 的存在正是您想要的:

while data := fgetcsv(fh, 1000, ",") != False:
    pass

(如果存在 fgetcsv 函数)

2013 年回答: 你不能在 Python 中做到这一点,在表达式中没有赋值。至少这意味着您不会不小心输入 == 而不是 = 或相反的方式并让它工作。

传统的 Python 风格是只使用 while True 和 break:

while True:
    data = fgetcsv(fh, 1000, ",")
    if not data:
        break
    # Use data here

但现在我会把它放在生成器中:

def data_parts(fh):
    while True:
        data = fgetcsv(fh, 1000, ",")
        if not data:
            break
        yield data

这样在使用该文件的代码中,丑陋的东西就被隐藏了:

for data in data_parts(fh):
    # Use data here

当然,如果您实际上是在读取 CSV,请使用 csv 模块。

【讨论】:

  • 谢谢。我将使用不定式循环。
  • @RemcoGerlich 一个简单的生成器而不是 while 循环的好例子。
【解决方案2】:

Python 3.8 pep-0572 现在使用新的符号 := 解决这种情况。看看:)

例如:

while chunk := file.read(8192):
   process(chunk)

【讨论】:

    【解决方案3】:

    您不能在表达式中使用赋值。赋值本身就是一个语句,不能组合 Python 语句。

    这是语言设计者做出的明确选择;很容易意外地使用一个 = 并分配,而您原本打算使用两个 == 并测试是否相等。

    将赋值移入循环,或赋值之前循环,并在循环本身中赋值。

    对于您的具体示例,Python csv module 为您提供了更高级别的 API,而您将循环访问 csv.reader()

    with open(csvfilename, 'rb') as csvfh:
        reader = csv.reader(csvfh)
        for row in reader:
    

    如果有的话,我很少需要在循环构造中进行分配。通常有一种(很多)更好的方法来解决手头的问题。

    也就是说,从 Python 3.8 开始,该语言实际上将具有赋值表达式,使用 := 作为赋值运算符。见PEP 572。赋值表达式在列表推导中实际上很有用,例如,当您需要在正在构建的列表中包含方法返回值并且需要能够在测试中使用该值时。

    现在,您必须使用生成器表达式:

    absolute = (os.path.abspath(p) for p in files)
    filtered = [abs for abs in absolute if included(abs)]
    

    但使用赋值表达式,您可以内联 os.path.abspath() 调用:

    filtered = [abs for p in files if included(abs := os.path.abspath(p))]
    

    【讨论】:

    • 谢谢。我实际上需要这个而不是 csv ,如果我感到困惑,对不起。
    • @BorutFlis:当然可以,但同样,请务必检查实现这一目标的更好方法。
    • 刚刚学习 Python 并喜欢它的简洁性。这是让我感到不安的第一件事,尽管我能理解语言设计者所做的选择......
    • @opncow:实际上,Python 3.8 会有一个赋值表达式。见PEP 572
    【解决方案4】:

    我写了一个小的 Python 模块,我称之为let,它允许您在任何允许函数的地方执行变量赋值。

    这样安装:

    pip install let
    

    我相信以下内容会满足您的需求:

    from let import let
    
    while let(data = fgetcsv(fh, 1000, ',')):
        # Do whatever you'd like with data here
    

    但是...邓肯的评论说使用iter 的原始问题很有趣。在他提出之前我不知道这个功能,现在我相信它可能是比我更好的解决方案。值得商榷 - iter 需要明确提供哨兵,而我的并不关心,只是等待 fgetcsv 返回任何 Falsey 值。

    【讨论】:

      猜你喜欢
      • 2016-01-13
      • 2011-07-12
      • 2011-12-08
      • 2010-11-11
      • 1970-01-01
      • 2019-06-09
      • 2010-10-07
      • 2020-10-27
      相关资源
      最近更新 更多