2009-09-13 6 views
15

J'ai eu quelques problèmes avec la syntaxe de compréhension de la liste en Python, alors j'ai commencé à réfléchir à la façon d'obtenir la même chose en Perl, ce que je connais mieux. J'ai réalisé que les exemples de base (pris de this page) peuvent tous être faits en Perl avec map ou grep.Les compréhensions de listes Python sont-elles identiques à celles de map/grep en Perl?

E.g.

(python)       (perl)     
S = [x**2 for x in range(10)]  @S = map { $_**2 } (0..9); 
V = [2**i for i in range(13)]  @V = map { 2**$_ } (0..12); 
M = [x for x in S if x % 2 == 0] @M = grep { $_ % 2 == 0 } @S; 

Ainsi « la compréhension de la liste » juste un terme de fantaisie pour « la carte et/ou filtrer une liste » ou est-il de plus?

Répondre

13

Vous avez raison: une liste de compréhension est essentiellement du sucre syntaxique pour carte et filtre (termes du monde de la programmation fonctionnelle).

Espérons que cet exemple de code démontre leur égalité:

>>> # Python 2 
>>> [x**2 for x in range(10)] == map(lambda x: x**2, range(10)) 
True 
>>> [2**i for i in range(13)] == map(lambda x: 2**x, range(13)) 
True 
>>> S = [x**2 for x in range(10)] 
>>> [x for x in S if x % 2 == 0] == filter(lambda x: x % 2 == 0, S) 
True 

Notez que ceci est valable uniquement en Python 2.X, comme SilentGhost a souligné dans le commentaire. Pour rendre ceci compatible avec Python 3, vous devrez encapsuler les appels à mapper ou filtrer dans le constructeur list, car la carte et le filtre ont été mis à jour pour renvoyer les itérateurs, pas les listes.

>>> # Python 3 
>>> [x**2 for x in range(10)] == list(map(lambda x: x**2, range(10))) 
True 
>>> [2**i for i in range(13)] == list(map(lambda x: 2**x, range(13))) 
True 
>>> S = [x**2 for x in range(10)] 
>>> [x for x in S if x % 2 == 0] == list(filter(lambda x: x % 2 == 0, S)) 
True 
+0

seulement pour py2k. – SilentGhost

0

Les compréhensions de liste sont plus puissantes que la carte ou le filtre car elles vous permettent de jouer abstraitement avec les listes.

Il est également plus pratique de les utiliser lorsque vos cartes sont imbriquées avec plus de cartes et d'appels de filtres.

+2

Pouvez-vous donner un exemple de ce que vous entendez par "jouer abstraitement avec des listes?" – friedo

3

Oui, ils sont fondamentalement identiques.

En Python fait a aussi une fonction de carte:

S = map(lambda x: x**2, range(10)) 

est le même que vos premiers exemples ci-dessus. Cependant, la syntaxe de compréhension de liste est fortement préférée en Python. Je crois que Guido a été cité comme s'il regrettait d'avoir introduit la syntaxe fonctionnelle.

Cependant, où il devient vraiment intéressant est dans la prochaine évolution de la compréhension de la liste, qui est générateurs. Ceux-ci vous permettent de renvoyer un itérateur - plutôt que de traiter toute la liste à la fois, il ne fait qu'une seule itération et revient ensuite, de sorte que vous n'avez pas besoin de garder toute la liste en mémoire en même temps. Très puissant.

+0

Je prends un générateur est essentiellement ce que les autres langues appellent un itérateur? – friedo

+1

@friedo un itérateur est un modèle, les générateurs sont un moyen de mettre en œuvre ce modèle – fortran

0

Oui. La puissance de la syntaxe Python est que la même syntaxe (entre ronds plutôt que crochets) est également utilisée pour définir des générateurs, qui produisent des séquences de valeurs à la demande.

2

Ils sont la version « pythonique » pour les séquences de cartographie et de filtrage, mais ils permettent de faire quelques autres choses, comme aplatir une liste imbriquée (niveau fixe), par exemple:

[j for i in nested_list for j in i] 

Une autre chose que vous ne pouvez pas faire avec un carte régulière et une expression lambda est de décomposer structurellement les valeurs itérer par exemple:

[(x%y)*z for x,y,z in list_with_triplets_of_ints] 

Bien sûr il y a des solutions de contournement comme:

aux = lambda x,y,z: (x%y)*z 
map(lambda t: aux(*t), list_with_triplets_of_ints) 

mais quand la transformation que vous devez appliquer est déjà définie, généralement, il est juste plus simple d'utiliser une carte, comme dans:

map(int, list_of_str_values) 

plutôt que

[int(i) for i in list_of_str_values] 
+0

+ 1 merci. J'aime particulièrement l'exemple du triplet; C'est difficile à faire succinctement avec la carte. – friedo

2

Liste compréhensions aussi Aplatir les choses:

Par exemple:

[(x, y) pour x dans xrange (10) si x% 2 == 0 pour y dans xrange (20) si x! = Y]

Si vous avez utilisé des cartes imbriquées ici, vous devez utilisez la concat (additionnant les listes) aussi.

Questions connexes