¿Es posible implementar un Python para un bucle de rango sin una variable de iterador?

StackOverflow https://stackoverflow.com/questions/818828

  •  03-07-2019
  •  | 
  •  

Pregunta

¿Es posible seguir sin el i ?

for i in range(some_number):
    # do something

Si solo quieres hacer algo N cantidad de veces y no necesitas el iterador.

¿Fue útil?

Solución

Fuera de la parte superior de mi cabeza, no.

Creo que lo mejor que podrías hacer es algo como esto:

def loop(f,n):
    for i in xrange(n): f()

loop(lambda: <insert expression here>, 5)

Pero creo que puedes vivir con la variable extra i .

Aquí está la opción de usar la variable _ , que en realidad es solo otra variable.

for _ in range(n):
    do_something()

Tenga en cuenta que a _ se le asigna el último resultado que se obtuvo en una sesión interactiva de python:

>>> 1+2
3
>>> _
3

Por esta razón, no lo usaría de esta manera. No conozco ningún idioma como lo menciona Ryan. Puede confundir a su intérprete.

>>> for _ in xrange(10): pass
...
>>> _
9
>>> 1+2
3
>>> _
9

Y de acuerdo con Gramática de Python , es un nombre de variable aceptable :

identifier ::= (letter|"_") (letter | digit | "_")*

Otros consejos

Puede que estés buscando

for _ in itertools.repeat(None, times): ...

esta es LA forma más rápida de iterar veces veces en Python.

El lenguaje general para asignar un valor que no se usa es nombrarlo _ .

for _ in range(times):
    do_stuff()

Lo que todo el mundo sugiere que use _ no dice que _ se usa con frecuencia como un acceso directo a uno de los gettext funciona, por lo que si desea que su software esté disponible en más de un idioma, es mejor que evite usarlo para otros fines.

import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print _('This is a translatable string.')

Aquí hay una idea aleatoria que utiliza (¿abusos?) el modelo de datos ( enlace de Py3 ).

class Counter(object):
    def __init__(self, val):
        self.val = val

    def __nonzero__(self):
        self.val -= 1
        return self.val >= 0
    __bool__ = __nonzero__  # Alias to Py3 name to make code work unchanged on Py2 and Py3

x = Counter(5)
while x:
    # Do something
    pass

¿Me pregunto si hay algo como esto en las bibliotecas estándar?

Puede usar _11 (o cualquier número u otro identificador no válido) para evitar la colisión de nombres con gettext. Cada vez que usa guión bajo + identificador inválido, obtiene un nombre ficticio que puede usarse para bucle.

¿La respuesta dependerá de qué problema tenga con el uso de iterador? se puede utilizar

i = 100
while i:
    print i
    i-=1

o

def loop(N, doSomething):
    if not N:
        return
    print doSomething(N)
    loop(N-1, doSomething)

loop(100, lambda a:a)

pero francamente no veo ningún punto en el uso de tales enfoques

t=0    
for _ in range(10):
    print t
    t = t+1

SALIDA:

0
1 
2 
3 
4 
5 
6 
7
8
9

Generalmente estoy de acuerdo con las soluciones dadas anteriormente. A saber:

  1. Usando el guión bajo en para -loop (2 y más líneas)
  2. Definición de un normal mientras que contador (3 y más líneas)
  3. Declaración de una clase personalizada con implementación __nonzero__ (muchas más líneas)

Si uno es definir un objeto como en # 3 , recomendaría implementar el protocolo para con palabra clave o aplique contextlib .

Además, propongo otra solución. Es un revestimiento de 3 y no es de la elegancia suprema, pero utiliza el paquete itertools y, por lo tanto, puede ser de su interés.

from itertools import (chain, repeat)

times = chain(repeat(True, 2), repeat(False))
while next(times):
    print 'do stuff!'

En este ejemplo, 2 es el número de veces que se repite el ciclo. cadena está envolviendo dos iteradores repetidos , el primero es limitado pero el segundo es infinito. Recuerde que estos son verdaderos objetos iteradores, por lo tanto, no requieren memoria infinita. Obviamente, esto es mucho más lento que la solución # 1 . A menos que esté escrito como parte de una función, puede requerir una limpieza por veces variable.

Nos hemos divertido bastante con lo siguiente, interesante para compartir:

class RepeatFunction:
    def __init__(self,n=1): self.n = n
    def __call__(self,Func):
        for i in xrange(self.n):
            Func()
        return Func


#----usage
k = 0

@RepeatFunction(7)                       #decorator for repeating function
def Job():
    global k
    print k
    k += 1

print '---------'
Job()

Resultados:

0
1
2
3
4
5
6
---------
7

Si do_something es una función simple o puede envolverse en una, un simple map () puede do_something rango (algún_número ) veces:

# Py2 version - map is eager, so it can be used alone
map(do_something, xrange(some_number))

# Py3 version - map is lazy, so it must be consumed to do the work at all;
# wrapping in list() would be equivalent to Py2, but if you don't use the return
# value, it's wastefully creating a temporary, possibly huge, list of junk.
# collections.deque with maxlen 0 can efficiently run a generator to exhaustion without
# storing any of the results; the itertools consume recipe uses it for that purpose.
from collections import deque

deque(map(do_something, range(some_number)), 0)

Si desea pasar argumentos a do_something , también puede encontrar el itertools repeatfunc receta se lee bien:

Para pasar los mismos argumentos:

from collections import deque
from itertools import repeat, starmap

args = (..., my args here, ...)

# Same as Py3 map above, you must consume starmap (it's a lazy generator, even on Py2)
deque(starmap(do_something, repeat(args, some_number)), 0)

Para pasar diferentes argumentos:

argses = [(1, 2), (3, 4), ...]

deque(starmap(do_something, argses), 0)

En lugar de un contador innecesario, ahora tiene una lista innecesaria. La mejor solución es usar una variable que comience con " _ " ;, que le diga a los verificadores de sintaxis que usted sabe que no está usando la variable.

x = range(5)
while x:
  x.pop()
  print "Work!"

Si realmente desea evitar poner algo con un nombre (ya sea una variable de iteración como en el OP, o una lista no deseada o un generador no deseado que devuelva la cantidad de tiempo deseada), puede hacerlo si realmente querías:

for type('', (), {}).x in range(somenumber):
    dosomething()

El truco que se usa es crear una clase anónima tipo ('', (), {}) que da como resultado una clase con un nombre vacío, pero NB que no está insertada en el local o espacio de nombres global (incluso si se proporcionó un nombre no vacío). Luego, utiliza un miembro de esa clase como variable de iteración que no se puede acceder, ya que la clase de la que es miembro es inalcanzable.

¿Qué pasa con:

while range(some_number):
    #do something
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top