2013-05-10 22 views
55

Stavo cercando il codice per far girare un cursore nel terminale e ho trovato questo. Mi stavo chiedendo cosa stava succedendo nel codice. In particolare for c in spinning_cursor(): non ho mai visto questa sintassi. È perché sto restituendo un elemento da un generatore alla volta con yield e questo è assegnato a c? Qualche altro esempio di questo per x in y() usa?per x in y(): come funziona?

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') 
+2

Un altro esempio? per i in range (10): print (i) – antoyo

+0

potresti trovare tutto qui: http://stackoverflow.com/questions/231767/the-python-yield-keyword-explained – pylover

+0

Un altro esempio di come la resa stava funzionando con una funzione qui ... Non ho bisogno di un esempio ora che ho capito. Inoltre, grazie @pylover – Paul

risposta

38

Utilizzando yield trasforma una funzione in una generator. Un generatore è un tipo specializzato di iterator. for scorre sempre su iterables, prendendo ogni elemento a turno e assegnandolo al nome (i) che hai elencato.

spinning_cursor() restituisce un generatore, il codice all'interno di spinning_cursor() non viene effettivamente eseguito finché non si avvia il iterazione sul generatore. L'iterazione su un generatore significa che il codice nella funzione viene eseguito fino a quando non incontra un'istruzione yield, a quel punto il risultato dell'espressione viene restituito come valore successivo e l'esecuzione viene nuovamente messa in pausa.

Il ciclo for si limita a questo, chiameremo l'equivalente di next() sul generatore, fino a quando il generatore segnali è fatto alzando StopIteration (che avviene quando la funzione restituisce). Ogni valore restituito di next() viene assegnato, a sua volta, a c.

si può vedere questo creando il generatore nel prompt di 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) 
'|' 

Questo generatore specifico restituisce mai, così StopIteration non è mai sollevato e il ciclo for andrà avanti per sempre a meno che non si uccide lo script.

+5

Waaaay troppo veloce. – pcalcao

+0

Grazie Martijn. L'idea è di chiamare una funzione e mentre è in elaborazione, visualizzare questo cursore rotante. Al termine dell'elaborazione, viene arrestato. Quindi lavorerò su questo. Grazie per la magnifica risposta. – Paul

2

la funzione spinning_cursor restituisce un iterabile (un generatore dalla resa).

for c in spinning_cursor(): 

sarebbe lo stesso di

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

In Python, l'istruzione for permette di eseguire iterazioni sugli elementi.

Secondo il documentation:

Python di per un'iterazione sulle voci di una qualsiasi sequenza (una lista o una stringa), nell'ordine in cui appaiono nella sequenza

Qui, il l'elemento sarà il valore restituito di spinning_cursor().

3

La sintassi for c in spinning_cursor() è un ciclo for-each. Sta per scorrere tutti gli elementi nell'iteratore restituito da spinning_cursor().

L'interno del ciclo sarà:

  1. scrive il carattere standard out e filo in modo che visualizzi.
  2. Dormire per un decimo di secondo
  3. Scrivere \b, che viene interpretato come un backspace (elimina l'ultimo carattere).Si noti che questo accade al termine del ciclo in modo che non sarà scritto durante la prima iterazione, e che condivide la chiamata filo nel passaggio 1.

spinning_cursor() sta per restituire un generator, che non fa in realtà corri finché non inizi a iterare. Sembra che passerà per lo '/-\|', in ordine, per sempre. È un po 'come avere una lista infinita per scorrere.

Quindi, l'output finale sarà uno spinner ASCII. Vedrai questi personaggi (nello stesso punto) ripetere fino a quando non uccidi la sceneggiatura.

/ 
- 
\ 
| 
2

Martijn La spiegazione di Pieters è eccellente. Di seguito è riportata un'altra implementazione dello stesso codice che hai inserito nella domanda. utilizza itertools.cycle per produrre lo stesso risultato di spinning_cursor. itertools è pieno di eccellenti esempi di iteratori e funzioni per aiutare a creare i propri iteratori. Potrebbe aiutarti a capire meglio gli iteratori.

import sys, time, itertools 

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

Grandi cose grazie. – Paul

Problemi correlati