Partage
  • Partager sur Facebook
  • Partager sur Twitter

Liste en compréhension

Une remarque sur le caractère intuitif ... ou pas

    25 octobre 2011 à 22:51:45

    Bonjour


    J'ai toujours trouvé les listes en compréhension assez intuitives. En fait, je viens de me rendre compte que ce n'était pas si clair.

    Soient les listes en compréhension imbriquées suivantes :

    print [[x,y] for x in range(0,2) for y in range(0,3)]
    


    Je pensais très intuitivement que la liste était générée dans l'ordre suivant :

    -- je fixe y à 0 et je fais varier x entre 0 et 1 PUIS
    -- je fixe y à 1 et je fais varier x entre 0 et 1 PUIS
    -- je fixe y à 2 et je fais varier x entre 0 et 1.

    Ça me paraissait logique puisque le for contenant y est le plus externe. Et bien pas du tout, c'est le contraire : on fixe d'abord x puis on fait varier y

    >>> print [[x,y] for x in range(0,2) for y in range(0,3)]
    [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]]
    >>>
    


    autrement dit, pour traduire en instructions for, on ne tient pas compte de for plus ou moins interne dans la liste de compréhension mais on récrit en lisant la liste en compréhension de gauche à droite :

    >>> L=[]
    >>> for x in range(0,2):
    	 for y in range(0,3):
    		 L.append([x,y])
    
    		 
    >>> L
    [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]]
    >>>
    



    La plupart du temps, l'inversion est indolore car on utilise ce genre de techniques pour initialiser une matrice avec des zéros ou pour transformer la liste en ensemble.

    Suis-je le seul à m'être mépris ?

    Et j'en conclus qu'on peut donc écrire des choses très contre-intuitives avec une liste en compréhension, genre :

    print [[x,y] for x in range(0,8) if x %5 ==1  if x>=2 for y in range(0,3) if x+y>3 for x in [10,11,12] for y in range(5)]
    


    mais une fois qu'on le sait ce n'est pas si mal pratique.
    • Partager sur Facebook
    • Partager sur Twitter
      26 octobre 2011 à 10:27:37

      Personnellement, ça me semble plus logique ainsi puisque le for est utilisé "de façon postfixe" par rapport à l'expression de base, ce qui veut dire que l'ordre d'imbrication des boucles doit être logiquement inversé.

      Ça ne m'a jamais choqué…

      Edit : Une sorte d'associativité à gauche, en fait :

          expression(x, y) for x in [...]  for y in [...] = ((expression(x, y) for x in [...]) for y in [...])
      • Partager sur Facebook
      • Partager sur Twitter
      Zeste de Savoir, le site qui en a dans le citron !
        26 octobre 2011 à 13:40:38

        Les parenthèses changent le résultat, toutefois.

        Mais je suis d'accord avec l'explication de nohar, ça m'a toujours paru logique aussi.
        • Partager sur Facebook
        • Partager sur Twitter
          26 octobre 2011 à 14:41:23

          Oui, le pseudo-code que j'ai montré n'était pas du python : le parenthésage n'indique pas une expression génératice mais bien la "précédence/associativité" des boucles for.
          • Partager sur Facebook
          • Partager sur Twitter
          Zeste de Savoir, le site qui en a dans le citron !
            26 octobre 2011 à 15:50:44

            Citation : nohar



            Edit : Une sorte d'associativité à gauche,



            Je suppose que tu veux parler d'une associativité gauche/droite

            Citation : nohar


            expression(x, y) for x in [...]  for y in [...] = ((expression(x, y) for x in [...]) for y in [...])



            Non, ça c'est ce qu'il serait logique de comprendre mais justement, c'est le contraire, c'est de l'associativité droite/gauche : l'indice qui varie le plus vite est situé le plus à droite ; autrement dit dans une liste en compréhension, on doit lire quelque chose du genre

            for x in I for y in J for z in L for y in M


            comme si on avait écrit

            for x in I (for y in J (for z in L (for y in M)))


            [mais les parenthèses sont interdites dans du code réel].
            • Partager sur Facebook
            • Partager sur Twitter
              26 octobre 2011 à 16:16:12

              Ah oui en effet, j'avais survolé ton exemple un peu vite et cru voir ce que je m'attendais intuitivement à voir, au temps pour moi !

              Effectivement, c'est surprenant comme comportement.
              • Partager sur Facebook
              • Partager sur Twitter
              Zeste de Savoir, le site qui en a dans le citron !
                31 octobre 2011 à 0:36:36

                Personnellement l'ordre actuel me semble assez logique, en effet il reprend l'ordre de deux for imbriqué.

                De toutes façon peu import la manière dont cela est gérer ça ne sera jamais intuitif pour tout le monde ;)
                • Partager sur Facebook
                • Partager sur Twitter
                  31 octobre 2011 à 0:38:11

                  Je n'avais pas compris l'explication de nohar en fait. Je trouve également que le comportement est logique et intuitif, j'imagine que c'est une question d'apprentissage avant tout.
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Anonyme
                    31 octobre 2011 à 10:49:18

                    Citation

                    Je n'avais pas compris l'explication de nohar en fait. Je trouve également que le comportement est logique et intuitif, j'imagine que c'est une question d'apprentissage avant tout.



                    Je suis d'accord avec Fayden, je dirais que c'est une question d'habitude.
                    • Partager sur Facebook
                    • Partager sur Twitter
                      31 octobre 2011 à 10:58:54

                      Citation : Fayden

                      Je n'avais pas compris l'explication de nohar en fait. Je trouve également que le comportement est logique et intuitif, j'imagine que c'est une question d'apprentissage avant tout.



                      En tous cas, le tutorial officiel de python.org dit la chose suivante :

                      Citation : python.org tutorial

                      If you’ve got the stomach for it, list comprehensions can be nested. They are a powerful tool but – like all powerful
                      <...>
                      Special care has to be taken for the nested list comprehension:



                      Et d'ajouter assez malencontreusement :

                      Citation

                      To avoid apprehension when nesting list comprehensions, read from right to left.




                      alors que c'est le contraire. Mais comme le tutorial le montre, un usage fréquent, pour ne pas dire majoritaire est celui ci :


                      >>> mat = [
                      ... [1, 2, 3],
                      ... [4, 5, 6],
                      ... [7, 8, 9],
                      ... ]
                      >>> print [[row[i] for row in mat] for i in [0, 1, 2]]
                      [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
                      


                      et qui n'est pas un vrai emboitement de listes en compréhension.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        31 octobre 2011 à 12:38:58

                        Je suis un peu confus en lisant ton message, mais le code que tu montres est bel et bien un cas de nested comprehension lists (et pas le code du premier post du topic). Dans ce cas, on doit lire évidemment de la droite vers la gauche, syntaxe oblige.

                        Je ne considère pas le bout de code suivant comme une nested comprehension list :
                        [(x,y) for x in xs for y in ys]
                        

                        Ce n'est qu'une seule comprehension list, et question de syntaxe, on la lit de la gauche vers la droite.
                        • Partager sur Facebook
                        • Partager sur Twitter
                          31 octobre 2011 à 13:18:51

                          Citation : Fayden

                          nested comprehension lists (et pas le code du premier post du topic).



                          Effectivement, le tuto de Guido parle à juste titre de nested (on a bien des listes qui sont emboitées). Néanmoins, même si c'est un abus, il n'est pas scandaleux de parler de nested list comprehensions dans le cas de mon premier exemple car cela revient à faire des nested for loops. D'ailleurs, ce vocabulaire se rencontre, par exemple I finally understand nested comprehensions dont la teneur du message confirme au passage que la compréhension de listes en compréhension des clauses for successives n'est pas si immédiate à comprendre pour tout le monde.
                          • Partager sur Facebook
                          • Partager sur Twitter

                          Liste en compréhension

                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                          • Editeur
                          • Markdown