84

我正在寻找在终端中旋转光标的代码并找到了这个。我想知道代码中发生了什么。特别是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')
4

5 回答 5

53

Usingyield将一个函数变成了一个生成器。生成器是一种特殊类型的迭代器for总是循环遍历可迭代对象,依次获取每个元素并将其分配给您列出的名称。

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除非您终止脚本,否则循环将永远持续下去。

一个更无聊(但更有效)的替代方法是使用itertools.cycle()

from itertools import cycle

spinning_cursor = cycle('/-\|')
于 2013-05-10T13:42:18.160 回答
6

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

根据文档

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

在这里,元素将是 的返回值spinning_cursor()

于 2013-05-10T13:43:56.520 回答
3

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

循环内部将:

  1. 将字符写入标准输出并刷新以显示。
  2. 睡十分之一秒
  3. Write \b,它被解释为退格(删除最后一个字符)。请注意,这发生在循环结束时,因此它不会在第一次迭代期间被写入,并且它在步骤 1 中共享刷新调用。

spinning_cursor()将返回一个generator,直到你开始迭代它才会真正运行。看起来它将'/-\|'永远按顺序循环。这有点像有一个无限的列表来迭代。

因此,最终输出将是一个 ASCII 微调器。你会看到这些字符(在同一个地方)重复,直到你杀死脚本。

/
-
\
|
于 2013-05-10T13:44:23.443 回答
2

spin_cursor 函数返回一个可迭代对象(来自 yield 的生成器)。

for c in spinning_cursor():

将与

 for i in [1, 2, 3, 4]:
于 2013-05-10T13:43:21.983 回答
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')
于 2013-05-10T15:17:38.330 回答