for y in y():这是如何工作的?

时间:2013-05-10 13:38:53

标签: python generator yield

我一直在寻找代码来在终端中旋转光标并找到它。我想知道代码中发生了什么。特别是for c in spinning_cursor():我从未见过这种语法。是因为我一次使用yield从生成器返回一个元素,并将其分配给c?在y()中使用x的任何其他例子?

import sys
import time

def spinning_cursor():
    cursor='/-\|'
    i = 0
    while 1:
        yield cursor[i]
        i = (i + 1) % len(cursor)

for c in spinning_cursor():
    sys.stdout.write(c)
    sys.stdout.flush()
    time.sleep(0.1)
    sys.stdout.write('\b')

5 个答案:

答案 0 :(得分:46)

使用yield将函数转换为generator。生成器是iterator的特殊类型。 for总是循环遍历iterables,依次获取每个元素并将其分配给您列出的名称。

spinning_cursor()返回一个生成器,spinning_cursor()内的代码实际上不会运行,直到你开始迭代生成器。迭代生成器意味着函数中的代码被执行,直到它遇到yield语句,此时表达式的结果将作为下一个值返回并再次暂停执行。

for循环就是这样,它会在生成器上调用等效的next(),直到生成器发出信号通过引发StopIteration来完成(当函数发生时)回报)。每个返回值next()依次分配给c

您可以通过在Python提示符中创建生成器来查看:

>>> def spinning_cursor():
...     cursor='/-\|'
...     i = 0
...     while 1:
...         yield cursor[i]
...         i = (i + 1) % len(cursor)
... 
>>> sc = spinning_cursor()
>>> sc
<generator object spinning_cursor at 0x107a55eb0>
>>> next(sc)
'/'
>>> next(sc)
'-'
>>> next(sc)
'\\'
>>> next(sc)
'|'

这个特定的生成器永远不会返回,所以StopIteration永远不会被引发,for循环将永远继续,除非你杀死脚本。

答案 1 :(得分:5)

在Python中,for语句允许您迭代元素。

根据documentation

  

Python的for语句按照它们在序列中出现的顺序迭代任何序列(列表或字符串)的项目

此处,元素将是spinning_cursor()的返回值。

答案 2 :(得分:3)

for c in spinning_cursor()语法是for-each循环。它将迭代spinning_cursor()返回的迭代器中的每个项目。

循环内部将:

  1. 将字符写入标准输出并刷新,以便显示。
  2. 睡眠十分之一秒
  3. \b,它被解释为退格(删除最后一个字符)。请注意,这发生在循环结束时,因此在第一次迭代期间不会写入,并且它在步骤1中共享刷新调用。
  4. spinning_cursor()将返回generator,在您开始迭代之前,它实际上不会运行。看起来它将永远循环遍历'/-\|'。这有点像有一个无限的列表来迭代。

    因此,最终输出将是ASCII微调器。在你杀死剧本之前,你会看到这些角色(在同一个地方)重复。

    /
    -
    \
    |
    

答案 3 :(得分:2)

spinning_cursor函数返回一个iterable(来自yield的生成器)。

for c in spinning_cursor():

相同
 for i in [1, 2, 3, 4]:

答案 4 :(得分:2)

Martijn Pieters的解释非常好。下面是您在问题中使用的相同代码的另一个实现。它使用itertools.cycle生成与spinning_cursor相同的结果。 itertools充满了迭代器和函数的优秀示例,以帮助创建自己的迭代器。它可能会帮助您更好地理解迭代器。

import sys, time, itertools

for c in itertools.cycle('/-\|'):
    sys.stdout.write(c)
    sys.stdout.flush()
    time.sleep(0.1)
    sys.stdout.write('\b')