Modo più pitonico per eseguire un processo X volte


90

Qual è più pitonico?

While loop:

count = 0
while count < 50:
    print "Some thing"
    count = count + 1

Per loop:

for i in range(50):
    print "Some thing"

Modifica: non duplicare perché questo ha risposte per determinare quale è più chiaro, rispetto a come eseguire un intervallo senza "i", anche se è risultato il più elegante


9
Upvoting per compensare i voti negativi: se Lionel fa questa domanda, altri potrebbero avere la stessa domanda e le risposte seguenti saranno utili.
— Eric O Lebigot

2
Il termine "Pythonic" è stato abusato. È un sinonimo di "leggibile" e "facilmente comprensibile". Almeno in Python.
— darioo

Risposte:


115

Personalmente:

for _ in range(50):
    print "Some thing"

se non ti serve i. Se usi Python <3 e vuoi ripetere il ciclo molte volte, usalo xrangepoiché non è necessario generare l'intera lista in anticipo.


15
Attenzione però per _ essere mappato alla funzione di traduzione gettext.
— Gintautas Miliauskas

Grazie per questa risposta; questo era il motivo principale per cui non stavo usando il ciclo for perché avevo una variabile inutilizzata in "i".
— Lionel

6
_ è proprio come qualsiasi altra variabile. È solo nella REPL che ha un significato particolare. L'OP può anche restare i.
— vezult

2
@vezult Mi piace in quanto rende chiaro che la variabile non viene utilizzata nell'istruzione. C'è forse una ragione che mette in ombra questo per restare con il i?
— ryanjdillon

7
Sono un convinto sostenitore dell'aggiunta di pony, specialmente quando sembra appropriato ... per pony nella gamma (50): print ("neigh") #python 3
— Paul

3

Il ciclo for è decisamente più pitonico, poiché utilizza le funzionalità integrate di livello superiore di Python per trasmettere ciò che stai facendo in modo più chiaro e conciso. L'overhead di range vs xrange e l'assegnazione di una ivariabile inutilizzata derivano dall'assenza di un'istruzione come l' repeataffermazione di Verilog . Il motivo principale per attenersi alla soluzione for range è che altri modi sono più complessi. Per esempio:

from itertools import repeat

for unused in repeat(None, 10):
    del unused   # redundant and inefficient, the name is clear enough
    print "This is run 10 times"

L'uso della ripetizione al posto dell'intervallo qui è meno chiaro perché non è una funzione così nota e più complesso perché è necessario importarlo. Le guide di stile principali se hai bisogno di un riferimento sono PEP 20 - The Zen of Python e PEP 8 - Style Guide for Python Code .

Notiamo anche che la versione for range è un esempio esplicito utilizzato sia in riferimento linguaggio che nel tutorial , sebbene in tal caso venga utilizzato il valore. Significa che la forma è destinata ad essere più familiare dell'espansione while di un ciclo for in stile C.


Non sarebbe meglio usare direttamente la cosa ripetuta, cioè: for s in repeat('This is run 10 times', 10): print s??
— F1Rumors

Certamente! Ma la stampa nel codice di esempio era solo un esempio di una sezione di codice ripetuta, per la quale potrebbe non esserci un oggetto centrale.
— Yann Vernier

Lo sviluppatore del core Python afferma che questo è più veloce rispetto all'utilizzo di range() twitter.com/raymondh/status/1144527183341375488
— Chris_Rands

È davvero più veloce, perché non ha bisogno di cercare o creare un intoggetto diverso per ogni iterazione. Tuttavia, il tempo del programmatore può essere più prezioso del tempo di esecuzione.
— Yann Vernier

2

Se stai cercando gli effetti collaterali che si verificano all'interno del ciclo, personalmente sceglierei range() approccio.

Se ti interessa il risultato di qualunque funzione chiami all'interno del ciclo, sceglierei una comprensione o un mapapproccio di elenco . Qualcosa come questo:

def f(n):
    return n * n

results = [f(i) for i in range(50)]
# or using map:
results = map(f, range(50))

risultati = (f per i nell'intervallo (50))
— Luka Rahne

1
risultati = itertools.imap (f, range (50))
— Luka Rahne

@ralu, solo se non hai bisogno di un accesso ripetuto o casuale ai risultati.
— aaronasterling

2
risultato = tupla (risultati) ed è molto più veloce dell'elenco, poiché lo slicing su tupla è O (1)
— Luka Rahne

-3

Che ne dite di?

while BoolIter(N, default=True, falseIndex=N-1):
    print 'some thing'

o in un modo più brutto:

for _ in BoolIter(N):
    print 'doing somthing'

o se vuoi vedere l'ultima volta:

for lastIteration in BoolIter(N, default=False, trueIndex=N-1):
    if not lastIteration:
        print 'still going'
    else:
        print 'last time'

dove:

class BoolIter(object):

    def __init__(self, n, default=False, falseIndex=None, trueIndex=None, falseIndexes=[], trueIndexes=[], emitObject=False):
        self.n = n
        self.i = None
        self._default = default
        self._falseIndexes=set(falseIndexes)
        self._trueIndexes=set(trueIndexes)
        if falseIndex is not None:
            self._falseIndexes.add(falseIndex)
        if trueIndex is not None:
            self._trueIndexes.add(trueIndex)
        self._emitObject = emitObject


    def __iter__(self):
        return self

    def next(self):
        if self.i is None:
            self.i = 0
        else:
            self.i += 1
        if self.i == self.n:
            raise StopIteration
        if self._emitObject:
            return self
        else:
            return self.__nonzero__()

    def __nonzero__(self):
        i = self.i
        if i in self._trueIndexes:
            return True
        if i in self._falseIndexes:
            return False
        return self._default

    def __bool__(self):
        return self.__nonzero__()

-5

Non esiste un modo veramente pitonico di ripetere qualcosa. Tuttavia, è un modo migliore:

map(lambda index:do_something(), xrange(10))

Se devi superare l'indice, allora:

map(lambda index:do_something(index), xrange(10))

Considera che restituisce i risultati come raccolta. Quindi, se hai bisogno di raccogliere i risultati, può aiutare.


Non solo questo non è davvero migliore (overhead della chiamata di funzione, espressioni lambda meno conosciute, raccolta di risultati inutilizzati in un elenco), 10 non è un iterabile.
— Yann Vernier

Sì, xrange (10) non 10. Ho detto che è meglio perché non è necessario scrivere una funzione o creare un ciclo. Tuttavia, come ho detto, non esiste un vero modo pitonico. Ho cambiato il codice, grazie.
— Abi M.Sangarab
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.