2012-05-17 4 views
2

Il est courant d'exprimer des boucles comme compréhensions de liste:remplaçant en boucle avec la compréhension de la liste

mylist=[] 
for i in range(30): 
    mylist.append(i**2) 

Cela équivaut à:

mylist = [i**2 for i in range(30)] 

Y at-il sorte de mécanisme par lequel ce genre de l'itération pourrait être faite avec une boucle while?

mylist=[] 
i=0 
while i<30: 
    mylist.append(i**2) 
    i+=1 

Bien sûr, avec cet exemple simple, il est facile de se traduire par une boucle for puis à une compréhension de la liste, mais s'il est pas si facile?

par exemple.

mylist = [i**2 while i=0;i<30;i++ ] 

(Bien sûr, le pseudo-code ci-dessus n'est pas python légitime) (itertools vient à l'esprit pour ce genre de chose, mais je ne sais pas ce module terriblement bien.)

EDIT

un exemple (très simple) où je pense qu'une compréhension while serait utile serait:

dt=0.05 
t=0 
mytimes=[] 
while t<maxtime: 
    mytimes.append(t) 
    t+=dt 

Cela pourrait se traduire par:

dt=0.05 
t=0 
nsteps=maxtime/dt 
mytimes=[] 
for t in (i*dt for i in xrange(nsteps)): 
    mytimes.append(t) 

qui peut être écrit sous la forme d'une liste (composé) Compréhension:

nsteps=maxtime/dt 
mytimes=[t for t in (i*dt for i in xrange(nsteps)] 

Mais, je dirais que la boucle while est BEAUCOUP plus facile à lire (et non avoir des erreurs d'index) Aussi, que se passe-t-il si votre objet (dt) supporte '+' mais pas '*'? Des exemples plus compliqués peuvent se produire si maxtime change d'une manière ou d'une autre pour chaque itération de la boucle ...

+3

« mais s'il est pas si facile? ": pouvez-vous donner un tel exemple?(qui n'est pas traduisible en une boucle for) – Pavel

+0

Que faire si la limite supérieure de la boucle change dans la boucle? par exemple. Que se passe-t-il si c'est alors que i <30 * math.sqrt (i): ... ' – mgilson

Répondre

9

Si votre boucle while vérifie une variable locale en cours d'incrémentation, vous devez la convertir en boucle for ou en compréhension de liste équivalente.

Vous ne devez utiliser une boucle while que si vous pouvez pas exprimer la boucle en cours d'itération sur quelque chose. Un exemple de cas d'utilisation typique est la vérification de l'état d'un Event ou d'une boucle de bas niveau qui appelle un code natif. Il s'ensuit que (correctement utilisé) alors que les boucles sont rares, et mieux juste écrites. Un alors que la compréhension les rendrait plus difficiles à lire.

Si vous voulez simplement renvoyer plusieurs valeurs, vous devriez envisager d'écrire generator.

Par exemple, votre algorithme modifié doit être écrit (en utilisant numpy.arange):

mytimes = numpy.arange(0, maxtime, 0.05) 

Sinon, avec un générateur:

def calcTimes(maxtime): 
    dt = 0.05 
    t = 0 
    while t < maxtime: 
    yield t 
    t += dt 
+0

Je ne suis pas d'accord avec le fait que les boucles ne doivent être utilisées que s'il est impossible d'itérer directement sur quelque chose. (J'ai posté un exemple où je pense que l'utilisation de 'while' est plus claire que l'utilisation d'une boucle' for' équivalente.) – mgilson

+0

@mgilson Modifié la réponse avec un interligne pour votre algorithme, et un générateur équivalent . Notez qu'un 'plage' non-entier est quelque chose que vous pouvez facilement implémenter dans un [helper generator] (http://stackoverflow.com/a/477610/35070). – phihag

+1

Je connais numpy.arange pour ce genre de choses - mais encore une fois, si vous écrivez une bibliothèque, vous ne voulez pas forcément forcer vos utilisateurs à télécharger et installer numpy juste pour que vous puissiez faire des choses comme ça. La fonction de générateur que vous avez posté est cependant (je pense) ce que je cherchais. Merci. – mgilson

Questions connexes