2010-07-09 4 views
3

De plus en plus de fonctionnalités de Python se déplacent pour être "paresseux exécutable", comme les expressions génératrices et d'autres types d'itérateurs. Parfois, cependant, je me vois vouloir rouler une boucle "pour" une ligne, juste pour effectuer une action.Quelle est la manière la plus pythonique d'avoir une expression de générateur exécutée?

Quelle serait la chose la plus pythonique pour que la boucle soit réellement exécutée?

Par exemple:

a = open("numbers.txt", "w") 
(a.write ("%d " % i) for i in xrange(100)) 
a.close() 

pas de code Actuall, mais vous voyez ce que je veux dire. Si j'utilise un générateur de liste, à la place, j'ai l'effet secondaire de créer une liste N-longueur remplie de "Aucun".

Actuellement, ce que je fais est d'utiliser l'expression comme argument dans un appel à "any" ou à "all". Mais je voudrais trouver un moyen qui ne dépende pas du résultat de l'expression effectuée dans la boucle - "any" et "all" peuvent s'arrêter en fonction de l'expression évaluée.

Pour être clair, ce sont des moyens de le faire que je connais déjà au sujet, et chacun a ses inconvénients:

[a.write ("%d " % i) for i in xrange(100))] 

any((a.write ("%d " % i) for i in xrange(100))) 

for item in (a.write ("%d " % i) for i in xrange(100)): pass 
+2

"Liste de longueur N remplie de moniales." –

+0

Juste pour clarifier: j'utilise rarement des choses comme ça dans le code de production - et étant donné les réactions ici, je vais probablement arrêter complètement, mais j'aime m'amuser à écrire des choses en ligne (même si elles ne sont pas pythoniques par nature). Hier encore, je me suis donné beaucoup de mal pour obtenir une doublure pour la méthode de la liste des "chunck" de ruby ​​1.9.2 (la version d'une ligne aspirée - mais une ligne supplémentaire déclarant Le dictionnaire devant un "générateur exécuté" donne à Python quelque chose de plus agréable que le "chunck" chose) – jsbueno

+0

@Nas: Arrêtez d'accuser au hasard les gens de choses qu'ils n'ont pas faites –

Répondre

5

Il y a beaucoup de accumulators qui ont pour effet de consommer toute l'itération qu'ils sont donnés, tels que min ou max - mais même ils n'ignorent pas entièrement les résultats obtenus dans le processus (min et max, par exemple, lèveront une exception si certains des résultats sont des nombres complexes). Je ne pense pas qu'il y ait un accumulateur intégré qui fait exactement ce que vous voulez - vous devez écrire (et ajouter à votre réserve personnelle de la fonction minuscule utilitaire) une fonction minuscule utilitaire tel que

def consume(iterable): 
    for item in iterable: pass 

La principale raison, je suppose, est que Python a une déclaration for et vous êtes censé l'utiliser quand il va comme un gant (c'est-à-dire, pour les cas que vous voulez consume pour ;-).

BTW, a.write retours None, ce qui est falsish, donc any consommera réellement (et a.writelines feront encore mieux!). Mais je réalise que vous donniez juste cela comme exemple ;-).

+0

En fait, il y a * façons * d'accomplir ce qui est demandé sans le défaut de 'min/max' - dans une ligne et sans créer de liste de len (N). J'ai trouvé 3 (trois) manières différentes après une bonne nuit de sommeil - mais dans les mots de [Fermat] (http://en.wikipedia.org/wiki/Fermat's_Last_Theorem) - 'Cette marge est trop étroite pour contenir [ cette preuve vraiment merveilleuse] ':-) –

+0

@Nas, il y a des façons maladroites évidentes telles que '[x pour x dans itérable si False]' (fait une liste vide) et similaire 'any (x et False pour x dans itérable) '(ne fait aucune liste du tout) et' all (x ou True pour x dans itérable) '- mais (bien qu'ils soient bien ajustés dans cette marge ;-) ils sont tous sérieux. –

+0

@Nas, bien ... n'hésitez pas à utiliser la page principale au lieu de la marge alors. :-) – jsbueno

7

Si je voulais faire cet exemple précis, j'écrirait

for i in xrange(100): a.write('%d ' % i) 

Si je devais souvent consommer un itérateur pour son effet, je définir

def for_effect(iterable): 
    for _ in iterable: 
     pass 

+0

Je pense que la boucle for est meilleure sur 2 lignes. Nous aimons les espaces d'indisponibilité de Python –

+0

Oui, je l'écrirais aussi de cette façon, mais l'OP ne connaissait peut-être pas la forme d'une ligne, et en a spécifiquement demandé une. –

10

Il y a une façon évidente de le faire, et c'est ainsi que vous devriez le faire. Il n'y a aucune excuse pour le faire d'une manière intelligente.

a = open("numbers.txt", "w") 
for i in xrange(100): 
    a.write("%d " % i) 
d.close() 

exécution Lazy vous donne un avantage sérieux: Il vous permet de passer d'une séquence à l'autre morceau de code sans avoir à tenir la chose entière en mémoire. C'est pour la création de séquences efficaces comme types de données.

Dans ce cas, vous ne voulez pas d'exécution paresseuse. Vous voulez l'exécution. Vous pouvez juste ... exécuter. Avec une boucle for.

Questions connexes