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.