2012-05-03 18 views
7

Recientemente comencé a aprender Python, y el concepto de for bucles todavía es un poco confuso para mí. Entiendo que generalmente sigue el formato for x in y, donde y es solo una lista.Para bucles (principiante)

El para-cada bucle for (int n: someArray) convierte for n in someArray,

Y el bucle for for (i = 0; i < 9; i-=2) puede ser representado por for i in range(0, 9, -2)

Supongamos que en lugar de un incremento constante, quería i*=2, o incluso i*=i. ¿Es esto posible, o tendré que usar un ciclo while en su lugar?

+0

su 'for i in range (0,9, -2)' no se repetirá si el primer número es menor que el segundo. – hexparrot

+0

Más exactamente, range() no puede proporcionar una matriz con un paso negativo para un valor positivo. Es un ciclo infinito. – dwerner

+0

@ user1320925 qué quiere estos como los valores de i: 1 2, 4 , 8, 16, 32 .... –

Respuesta

1

Usted tendrá que usar list comprehensions para este

print [x**2 for x in xrange(10)] # X to the 2nd power. 

y

print [x**x for x in xrange(10)] # X to the Xth power. 

La sintaxis comprensión de lista es la siguiente:

[EXPRESSION for VARIABLE in ITERABLE if CONDITION] 

Bajo el capó, que actúa de manera similar a la map and filter function:

def f(VARIABLE): return EXPRESSION 
def c(VARIABLE): return CONDITION 

filter(c, map(f, ITERABLE)) 

ejemplo dado:

def square(x): return x**2 

print map(square, xrange(10)) 

y

def hypercube(x): return x**x 

print map(hypercube, xrange(10)) 

que se puede utilizar como método alternativo si no' me gusta la lista de comprensiones. También podría usar un bucle for, pero eso dejaría de ser un idiomático de Python ...

+0

Crear una lista y luego recorrerla no es óptima, y ​​esa no es la sintaxis para una comp de lista (es una expresión, no una función, es una iterable, no una lista, y podría haber una instrucción if al final) –

+0

@Lattyware: es óptimo, es lo que hace una expresión de generador. Observe cómo su respuesta se vincula a la lista de comprensiones ...;) –

+0

No es cierto. Mi respuesta se relaciona con un video que hice que explica las listas de comprensión junto con las expresiones del generador y el dictado y establece las comprensiones. Las expresiones de generador son flojas, y por lo tanto ** muy ** diferentes a una lista de comprensión. Si hacemos un ciclo de cinco millones, su solución creará una lista de '0 * 2' a' 4999999 * 2', y luego lo repetirá. Una expresión del generador los calculará según sea necesario. –

11

Como dices, un bucle for recorre los elementos de una lista. La lista puede contener lo que quieras, por lo que puedes construir una lista de antemano que contenga cada paso.

Un bucle for también puede iterar sobre "generator", que es una pequeña porción de código en lugar de una lista real. En Python, range() es en realidad un generador (en Python 2.x embargo, range() devolvió una lista, mientras que xrange() fue el generador).

Por ejemplo:

def doubler(x): 
    while True: 
     yield x 
     x *= 2 

for i in doubler(1): 
    print i 

El for bucle de arriba se imprimirá

1 
2 
4 
8 

y así sucesivamente, hasta que se pulsa Ctrl + C.

+0

Diría que un generador independiente es excesivo para esto; una expresión de generador probablemente también lo haría. Por ejemplo, 'for i in (x * 2 for x in range (10)):' –

+1

Sí, puede escribir el código de forma más compacta. Sin embargo, creo que es instructivo mostrar lo que puede hacer un generador generalizado. –

+0

Si bien es bueno saber que puede hacer más con él, no es bueno aconsejar a las personas que compitan demasiado. Explicar también la sintaxis de la expresión del generador probablemente sería bueno, para evitar enviar al asker y hacer de los generadores muy simples funciones completas. –

8

Puede utilizar un generator expression hacer esto de manera eficiente y con poco código de exceso:

for i in (2**x for x in range(10)): #In Python 2.x, use `xrange()`. 
    ... 

expresiones generadoras de trabajo al igual que define un generador manual (como en Greg Hewgill's answer), con una sintaxis similar a una lista por comprensión. Se evalúan con pereza, lo que significa que no generan una lista al inicio de la operación, lo que puede causar un rendimiento mucho mejor en iterables grandes.

Por lo tanto, este generador funciona esperando hasta que se le solicite un valor, luego solicite range(10) para un valor, duplicando ese valor y devolviéndolo al lazo for. Hace esto repetidamente hasta que el generador range() no da más valores.

+2

@TomWijsman No creo que sea menos legible. Si realmente quisiera, podría hacer 'dobles = (x * 2 para x en el rango (10))' y luego repetir 'dobles'. Si lo comparas con tu respuesta, una lista de comprensión, literalmente hablamos de diferentes corchetes fuera de la expresión. ¿Cómo es eso menos legible o mantenible? –

+2

@TomWijsman Mi respuesta es un trazador de líneas único, y sugerir que una sola línea es siempre mejor que las líneas múltiples es una locura. A veces, más líneas son más legibles. En cuanto a la depuración ser más difícil, eso simplemente no es cierto. Como dije en mi otro comentario, hay una razón por la cual todos los builtins de Python 3 ahora son flojos, donde en 2.x produjeron listas. –

+1

@Lattyware Creo que OP quiere 2,4,8,16,32 ... y su solución da 2,4,6,8,10 .... –

5

Tenga en cuenta que la parte 'lista' de Python puede ser cualquier secuencia iterable.

Ejemplos:

Una cadena:

for c in 'abcdefg': 
    # deal with the string on a character by character basis... 

Un archivo:

with open('somefile','r') as f: 
    for line in f: 
     # deal with the file line by line 

Un diccionario:

d={1:'one',2:'two',3:'three'} 
for key, value in d.items(): 
    # deal with the key:value pairs from a dict 

Una rebanada de una lista:

l=range(100) 
for e in l[10:20:2]: 
    # ever other element between 10 and 20 in l 

, etc, etc, etc, etc

Por lo que realmente es mucho más profundo que 'sólo algunos lista'

Como otros han dicho, acaba de establecer la iterable a ser lo que usted quiere que sea para su preguntas ejemplo:

for e in (i*i for i in range(10)): 
    # the squares of the sequence 0-9... 

l=[1,5,10,15] 
for i in (i*2 for i in l): 
    # the list l as a sequence * 2... 
+0

+1 - Este es un buen punto. Para bucles, revise cualquier lista iterable, no solo. –

+0

No veo cómo responde esto a la pregunta. –

+0

@Tom Wijsman: El OP declara que 'el concepto de bucles for sigue siendo un poco confuso para mí. Entiendo que generalmente sigue el formato para x en y, donde y es solo una lista. "Estaba aclarando que y es mucho más que 'solo una lista' –

0

Sólo por una alternativa, ¿qué hay de la generalización de la operación iterate/Valor mínimo de una función lambda para que pueda hacer algo como esto:

for i in seq(1, 9, lambda x: x*2): 
    print i 
... 
1 
2 
4 
8 

Dónde seq se define a continuación:

#!/bin/python 
from timeit import timeit 

def seq(a, b, f): 
    x = a; 
    while x < b: 
     yield x 
     x = f(x) 

def testSeq(): 
    l = tuple(seq(1, 100000000, lambda x: x*2)) 
    #print l 

def testGen(): 
    l = tuple((2**x for x in range(27))) 
    #print l 

testSeq(); 
testGen(); 

print "seq", timeit('testSeq()', 'from __main__ import testSeq', number = 1000000) 
print "gen", timeit('testGen()', 'from __main__ import testGen', number = 1000000) 

La diferencia en el rendimiento no es mucho:

seq 7.98655080795 
gen 6.19856786728 

[EDIT]

Para apoyar iteración inversa y con un argumento predeterminado ...

def seq(a, b, f = None): 
    x = a; 
    if b > a: 
     if f == None: 
      f = lambda x: x+1 
     while x < b: 
      yield x 
      x = f(x) 
    else: 
     if f == None: 
      f = lambda x: x-1 
     while x > b: 
      yield x 
      x = f(x) 

for i in seq(8, 0, lambda x: x/2): 
    print i 

Nota: Esto comporta de manera diferente a range/xrange en el que la dirección del ensayo </> es elegido por el signo iterador, en lugar de la diferencia entre los valores inicial y final.