Una forma más pitónica de ejecutar un proceso X veces

90

¿Qué es más pitónico?

Mientras que bucle:

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

En bucle:

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

Editar: no duplicar porque tiene respuestas para determinar cuál es más claro, frente a cómo ejecutar un rango sin 'i', a pesar de que terminó siendo el más elegante

Lionel
fuente
8
Votar a favor para compensar los votos en contra: si Lionel hace esta pregunta, es posible que otros tengan la misma pregunta, y las respuestas a continuación serán útiles.
Eric O Lebigot
2
El término "Pythonic" se está usando en exceso. Es un sinónimo de "legible" y "fácilmente comprensible". En Python, al menos.
darioo
Posible duplicado de ¿Es posible implementar un bucle de rango de Python sin una variable de iterador?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

112

Personalmente:

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

si no lo necesita i. Si usa Python <3 y desea repetir el ciclo muchas veces, utilícelo xrangeya que no es necesario generar la lista completa de antemano.

Felix Kling
fuente
15
Sin embargo, tenga cuidado con que _ se asigne a la función de traducción gettext.
Gintautas Miliauskas
Gracias por esta respuesta; esta fue la razón principal por la que no estaba usando el bucle for porque tenía una variable sin usar en "i".
Lionel
6
_ es como cualquier otra variable. Solo en el REPL tiene un significado particular. El OP también puede quedarse i.
vezult
2
@vezult Me gusta esto porque deja en claro que la variable no se está utilizando en la declaración. ¿Hay quizás una razón que eclipsa esto para seguir con el i?
ryanjdillon
6
Soy un firme creyente en agregar ponis, especialmente cuando suena apropiado ... para pony en el rango (50): print ("neigh") #python 3
Paul
3

El bucle for es definitivamente más pitónico, ya que utiliza la funcionalidad incorporada de nivel superior de Python para transmitir lo que estás haciendo de manera más clara y concisa. La sobrecarga de range vs xrange, y la asignación de una ivariable no utilizada , provienen de la ausencia de una declaración como la repeatdeclaración de Verilog . La razón principal para ceñirse a la solución de rango for es que otras formas son más complejas. Por ejemplo:

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"

El uso de repetir en lugar de rango aquí es menos claro porque no es una función tan conocida y más complejo porque necesita importarlo. Las principales guías de estilo si necesita una referencia son PEP 20 - The Zen of Python y PEP 8 - Style Guide for Python Code .

También notamos que la versión for range es un ejemplo explícito que se usa tanto en la referencia del lenguaje como en el tutorial , aunque en ese caso se usa el valor. Significa que la forma seguramente será más familiar que la expansión while de un bucle for estilo C.

Yann Vernier
fuente
¿No sería mejor usar lo repetido directamente, es decir: for s in repeat('This is run 10 times', 10): print s??
F1Rumors
¡Ciertamente! Pero la impresión en el código de muestra era solo un ejemplo de una sección repetida de código, para la cual puede que no haya un objeto central.
Yann Vernier
El desarrollador central de Python dice que esto es más rápido que usar range() twitter.com/raymondh/status/1144527183341375488
Chris_Rands
De hecho, es más rápido, porque no necesita buscar o crear un intobjeto diferente para cada iteración. Sin embargo, el tiempo del programador puede ser más valioso que el tiempo de ejecución.
Yann Vernier
2

Si buscas los efectos secundarios que ocurren dentro del ciclo, personalmente optaría por el range()enfoque.

Si le importa el resultado de las funciones que llame dentro del ciclo, optaría por una lista de comprensión o mapenfoque. Algo como esto:

def f(n):
    return n * n

results = [f(i) for i in range(50)]
# or using map:
results = map(f, range(50))
knutin
fuente
resultados = (f para i en el rango (50))
Luka Rahne
1
resultados = itertools.imap (f, range (50))
Luka Rahne
@ralu, solo si no necesita acceso repetido o aleatorio a los resultados.
aaronasterling
2
resultado = tupla (resultados) y es mucho más rápido que la lista, ya que cortar en tupla es O (1)
Luka Rahne
-3

¿Qué tal si?

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

o de una manera más fea:

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

o si quieres ver la última vez a través de:

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

dónde:

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__()
DangerMouse
fuente
-5

No existe una forma realmente pitónica de repetir algo. Sin embargo, es una mejor manera:

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

Si necesita pasar el índice, entonces:

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

Considere que devuelve los resultados como una colección. Por lo tanto, si necesita recopilar los resultados, puede ayudar.

Abi M. Sangarab
fuente
Esto no solo no es realmente mejor (sobrecarga de llamadas de función, expresiones lambda menos conocidas, recopilación de resultados no utilizados en una lista), 10 no es iterable.
Yann Vernier
Sí, xrange (10) no 10. Dije que es mejor porque no necesitas escribir una función o hacer un bucle. Sin embargo, como dije, no existe una forma pitónica real. Cambié el código, gracias.
Abi M. Sangarab