Simulación de estilo C para loops en python.

(Incluso el título de esto va a causar llamas, me doy cuenta)

Python tomó la decisión de diseño deliberado para tener el uso en bucle explícito de iterables, con el beneficio de un código considerablemente simplificado en la mayoría de los casos.

Sin embargo, a veces es bastante complicado construir un iterable si tu caso de prueba y la función de actualización son complicados, por lo que me encuentro escribiendo los siguientes bucles while:

 val = START_VAL while : # do stuff ... val =  

El problema con esto es que la actualización está en la parte inferior del bloque while , lo que significa que si quiero tener un continue incrustado en algún lugar, tengo que:

  • usar código duplicado para la actualización complicada / awkard, Y

  • corre el riesgo de olvidarlo y tener mi bucle infinito de código

Podría seguir la ruta de rodar a mano un complicado iterador:

 def complicated_iterator(val): while : yeild val val =  for val in complicated_iterator(start_val): if : continue # no issues here # do stuff 

Esto me parece que es demasiado detallado y complicado. ¿La gente en el desbordamiento de stack tiene una sugerencia más simple?

Respuesta a los comentarios:

@Glenn Maynard: Sí, descarté la respuesta. Es malo escribir cinco líneas si hay una manera de hacerlo en una … especialmente en un caso que surge todo el tiempo (el bucle es una característica común de los progtwigs completos de Turing).

Para las personas que buscan un ejemplo concreto: digamos que estoy trabajando con una biblioteca de fechas personalizada. Mi pregunta sería entonces, ¿cómo expressías esto en python?

 for (date = start; date < end; date = calendar.next_quarter_end(date)): if another_calendar.is_holiday(date): continue # ... do stuff... 

Esto es lo mejor que se me ocurre:

 def cfor(first,test,update): while test(first): yield first first = update(first) def example(blah): print "do some stuff" for i in cfor(0,lambda i:i 

Desearía que Python tuviera una syntax para expresiones cerradas.

Edición: Además, tenga en cuenta que solo tiene que definir cfor una vez (en contraposición a su función valor_complicado).

Qué pasa:

 date = start while date < end: if not another_calendar.is_holiday(date): # ... do stuff... date = calendar.next_quarter_end(date) 

Pero si usa esa construcción en particular a menudo, es mejor que defina el generador una vez y lo reutilice como lo hizo en su pregunta.

(El hecho es que, dado que son idiomas diferentes, no es posible que todas las construcciones del mapa C se conviertan en una construcción más compacta en Python. Es como decir que se tiene un algoritmo de compresión que funciona igual de bien en todas las entradas aleatorias).

Estoy un poco confundido: ¿tienes una expresión de expresión complicada y otra de expresión complicada, pero encajan bien en un bucle de C para? Eso no tiene sentido para mí.

Recomiendo el enfoque iterador personalizado. Es probable que encuentre otros usos para el iterador, y encapsular la iteración es una buena práctica de todos modos.

ACTUALIZACIÓN: Usando su ejemplo, definitivamente haría un iterador personalizado. Me parece perfectamente natural que un calendario pueda generar una serie de fechas trimestrales:

 class Calendar: # ... def quarters(self, start, end): """Generate the quarter-start dates between `start` and `end`.""" date = start while date < end: yield date date = self.next_quarter_end(date) for date in calendar.quarters(start, end): if another_calendar.is_holiday(date): continue # ... do stuff... 

Esto parece ser una maravillosa abstracción para su clase de calendario, y apuesto a que la usará más de una vez.

Podría usar una cláusula try / finally para ejecutar la actualización:

 val = START_VAL while : try: # do stuff continue finally: val =  

Advertencia: esto también ejecutará la instrucción de actualización si haces un break .

A menudo hago

 while True: val =  if not val: break etc. 

Heh

 def forre(a,i,c,top,increment,run): increment = increment.replace("++","+=1").replace("--","-=1").replace("; ","") while i != top: try: exec(run) except: print "error: "; print run try: exec(increment) except: print "error: "; print increment forre("int i=",0,"; i<",6,"; i++", "print i" )