Подтвердить что ты не робот

Для x в y(): как это работает?

Я искал код для вращения курсора в терминале и нашел это. Мне было интересно, что происходит в коде. В частности, for c in spinning_cursor(): я никогда не видел этот синтаксис. Это потому, что я возвращаю один элемент из генератора за раз с yield, и ему присваивается c? Любые другие примеры этого для x в y() используют?

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')
4b9b3361

Ответ 1

Использование yield превращает функцию в генератор. Генератор - это специализированный тип итератора. 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() более скучной (но более эффективной) альтернативой было бы использование itertools.cycle():

from itertools import cycle

spinning_cursor = cycle('/-\|')

Ответ 2

В Python оператор for позволяет перебирать элементы.

По документации:

Питон для оператора перебирает элементы любой последовательности (список или строка) в том порядке, в котором они появляются в последовательности

Здесь элементом будет возвращаемое значение spinning_cursor().

Ответ 3

Синтаксис for c in spinning_cursor() - это цикл for-each. Он будет проходить через каждый элемент в итераторе, возвращенный spinning_cursor().

Внутренняя часть цикла будет:

  • Введите символ в стандартный и скрытый, чтобы он отображался.
  • Сон на десятую часть секунды
  • Напишите \b, который интерпретируется как обратное пространство (удаляет последний символ). Обратите внимание, что это происходит в конце цикла, поэтому он не будет записан во время первой итерации и что он разделяет вызов flush на шаге 1.

spinning_cursor() собирается вернуть generator, который фактически не запускается до тех пор, пока вы не начнете выполнять итерацию. Похоже, он будет проходить через '/-\|', чтобы, навсегда. Это похоже на бесконечный список итераций.

Таким образом, конечный результат будет AinnerII. Вы увидите, что эти символы (в том же месте) повторяются до тех пор, пока вы не убьете script.

/
-
\
|

Ответ 4

функция spinning_cursor возвращает итерабельность (генератор с выходом).

for c in spinning_cursor():

будет таким же, как

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

Ответ 5

Описание 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')