我们不能做类似 if (y = Foo()) > 2: in python 的事情吗?

Can't we do something like if (y = Foo()) > 2: in python?

我是 python 的新手。 在 C/C++ 中,在 while 或 if 语句中,我经常进行变量赋值。下面是一个简单的C++示例代码:

#include <iostream>

int Increment(const int x) {
  return (x + 1); 
}

int main(void) {
  int x = 2, y;
  while ((y = Increment(x)) > 2) {
    std::cout << "y is larger than 2" << std::endl;
  }

  return (0);
}

但以下 python 代码不起作用:

#!/usr/bin/python

def Increment(x):
  return x + 1

def main():
  x= 2
  while (y = Increment(x)) > 2:
    print "y is larger than 2"

if __name__ == "__main__"
  main()

报错信息如下:

   while (y = Increment(x)) > 2:
          ^
SyntaxError: invalid syntax

在python中好像不能在比较语句中进行变量赋值吧?那么,在 python 中执行此操作的最佳方法是什么?

def main():
x = 2
  y = Increment(x)
  while y > 2:
    print "y is larger than 2"
    y = Increment(x)

无法在 Python 中的表达式中分配变量。

然而,由于你的循环永远循环,并且 Increment(x) 没有副作用,你可以这样做(它在行为上是相同的):

def main():
    while True:
        print("y is larger than 2")

Python和C(或C++)的区别在于,在Python中赋值是一个语句,而在C(和C++)中赋值是一个表达式.

表达式可以是其他表达式的一部分,但语句是独立的。

不,但是您可以(必须)绑定到 for 循环中的变量。因此,对于您的示例,请尝试停止思考 C/C++ 并开始思考 Python:使用 for 循环并将 while 的条件部分移动到生成器中.

不幸的是,您的示例实际上没有做任何有用的事情并且永远循环,但是大多数真实示例将很快简化为比您使用 while.

获得的更清晰的东西

对于给出的示例,您甚至不需要生成器,只需重复调用 Increment(x)

#!/usr/bin/python

def Increment(x):
  return x + 1

def main():
  x= 2
  for y in iter(lambda: Increment(x)):
      if y <= 2: break
      print "y is larger than 2"

if __name__ == "__main__"
  main()

如果函数中有一个固定的 return 指示完成(例如 None 表示数据结束),那么 iter() 的两个参数版本很有用,您不需要'需要单独检查:

>>> def collatz(x):
    if x%2:
        return 3*x+1
    return x//2

>>> x = 5
>>> for y in iter(lambda: collatz(x), 1):
    print(y)
    x = y


16
8
4
2

生成器版本为:

>>> def collatz(x):
    while x != 1:
        x = 3*x+1 if x%2 else x//2
        yield x

>>> for y in collatz(7):
    print(y, end=' ')


22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1 

它巧妙地将复杂的循环逻辑与我们希望在每次迭代中执行的操作分开。

与其重复调用 Increment(),我会这样构建循环:

x = 2
while True:
    y = Increment(x);
    if not y > 2:
        break
    print "y is larger than 2"

The Python design FAQ 中也对此进行了讨论,建议使用相同的代码。

常见问题解答还提到使用迭代:

for y in itertools.repeat(Increment(x)):
    if not y > 2:
        break
    print "y is larger than 2"

或者:

from itertools import takewhile, repeat
for y in takewhile(lambda y: y > 2, repeat(Increment(x)):
    print "y is larger than 2"

这段代码实际上并不是每次都在循环中调用 Increment,它依赖于每次都是相同值的知识。但是正如 Duncan 的回答一样,您可以使用 iterlambda 来改变它。如果在循环中修改 x ,则需要进行此类操作。以下任何一个都将进行迭代,并且根据实际代码与此示例的不同之处,您可能希望将您的代码基于其中任何一个。例如,itertools.repeat(x) 很容易更改为 itertools.count(x)xrange(x) 或任何其他迭代器,而在 iter(lambda: x)x 很容易更改为您喜欢的任何其他表达式.

itertools.repeat(Increment(x))
iter(lambda: Increment(x))
itertools.imap(Increment, itertools.repeat(x))
itertools.imap(Increment, iter(lambda: x))

然后您可以将 itertools.takewhile 应用于其中任何一个。