Partage
  • Partager sur Facebook
  • Partager sur Twitter

Différence d'assignation de liste

Sujet résolu
    20 novembre 2019 à 11:00:02

    Bonjour,

    Entre:

    tt = [0,1]
     
    a1 = [tt]*4
    a2 = [tt for _ in range(4)]
    a3 = [[0,1]]*4
     
    a1[0][1] = 6
    a2[0][1] = 6
    a3[0][1] = 6
     
    print(a1)
    print(a2)
    print(a3)


    [[0, 6], [0, 6], [0, 6], [0, 6]]
    [[0, 6], [0, 6], [0, 6], [0, 6]]
    [[0, 6], [0, 6], [0, 6], [0, 6]]

    &:

       
    b1 = [[0,1] for _ in range(4)]
     
    b1[0][1] = 6
     
    print(b1)


    [[0, 6], [0, 1], [0, 1], [0, 1]]

    Je ne comprends pas la différence de résultat, pouvez-vous m'aider?

    • Partager sur Facebook
    • Partager sur Twitter
      20 novembre 2019 à 13:47:33

      Dans a1 tu références 4 fois la même liste, idem dans a2 et a3

      dans b1 tu crée 4 listes différentes.

      Un autre exemple :

      >>> a = [0,1,2]
      >>> b = a
      >>> b[0] = 9
      >>> print(a)
      [9, 1, 2]
      >>> print(b)
      [9, 1, 2]
      



      -
      Edité par thelinekioubeur 20 novembre 2019 à 13:47:57

      • Partager sur Facebook
      • Partager sur Twitter
        20 novembre 2019 à 21:04:54

        Très bonne question à laquelle thelinekioubeur a très bien répondu ; juste quelques détails.

        L'itération

        Si L représente une liste, l'opération L * n est équivalente à :

        • on évalue une fois l'objet L en M
        • on retourne la concaténation M + M + ... + M (n fois).

        Par exemple, le code suivant

        L = [[42, 81]] * 3
        print(L)
        
        L[2][1] = 1000
        print(L)
        
        

        est équivalent au code

        t = [42, 81]
        M = [t] + [t] + [t]
        print(M)
        
        M[2][1] = 1000
        print(M)
        
        

        et affichent tous les deux :

        [[42, 81], [42, 81], [42, 81]]
        [[42, 1000], [42, 1000], [42, 1000]]
        
        

        Toutefois, les deux codes suivants ne sont pas équivalents :

        t = [42, 81]
        M = [t] + [t] + [t]
        print(M)
        
        M[2][1] = 1000
        print(M)
        
        print("---------------")
        t = [42, 81]
        M = [[42, 81]] + [[42, 81]] + [[42, 81]]
        print(M)
        
        M[2][1] = 1000
        print(M)
        
        

        qui affiche

        [[42, 81], [42, 81], [42, 81]]
        [[42, 1000], [42, 1000], [42, 1000]]
        ---------------
        [[42, 81], [42, 81], [42, 81]]
        [[42, 81], [42, 81], [42, 1000]]
        
        

        Noter que L * n ne vaut pas forcément L + L + ... + L (n fois).

        Liste en compréhension

        D'une manière générale, si expr désigne une expression, la liste en compréhension

        M = [expr for k in range(n)]
        
        

        est obtenue par le procédé suivant (à quelques nuances près en fait):

        M=[]
        
        for k in range(n):
            M.append(expr)
        print(M)
        
        

        Par conséquent, les deux codes suivants ne sont pas équivalents :

        expr = [42, 81]
        n = 3
        M = [expr for k in range(n)]
        
        print(M)
        
        M[2][1] = 1000
        
        print(M)
        
        

        qui affiche

        [[42, 81], [42, 81], [42, 81]]
        [[42, 1000], [42, 1000], [42, 1000]]
        
        

        à comparer avec

        n = 3
        M = [[42, 81] for k in range(n)]
        
        print(M)
        
        M[2][1] = 1000
        
        print(M)
        
        

        qui affiche

        [[42, 81], [42, 81], [42, 81]]
        [[42, 81], [42, 81], [42, 1000]]
        
        

        En effet, dans le premier cas, c'est toujours le même objet (avec la même id) qui est placé dans la liste en compréhension ; dans le 2e code, à chaque insertion c'est une liste d'id différente qui est insérée.

        -
        Edité par PascalOrtiz 20 novembre 2019 à 22:49:33

        • Partager sur Facebook
        • Partager sur Twitter
          26 novembre 2019 à 22:26:21

          Merci beaucoup pour vos réponses.

          Effectivement chaque liste référence n fois la même sous liste.
          En fait a1 & a2 sont assignées par une opération sur une variable.
          Cette variable (tt) est assignée par une liste qui contient 2 éléments (0 &1).
          tt possède donc une id ainsi que les éléments qui la constituent.

          a1 est assigné par une multiplication par n de tt.
          Selon la nature de tt (une liste) a1 sera une liste et a1 contiendra donc n fois la sous liste tt.
          a1 en tant que liste principale possède donc sa propre id et référence n fois l'id de tt et de ses éléments.

          a2 est aussi une liste principale qui possède par conséquent sa propre id, mais contrairement à a1, elle est assignée (sous la forme d'une liste en compréhension) par tt dans une boucle for  ; ce qui entraîne une réévaluation de l'élément à traiter. tt est donc réévalué n fois comme étant tt avec sa propre id et celles des éléments qui la composent.
          Quel que soit le processus d'assignation choisi, a1 & a2 référencent  donc obligatoirement toutes les deux les id de tt, que tt soit copiée (ou concaténée), ou réévalué.

          a3 est, comme a1, assignée par une multiplication par n, mais contrairement à a1, l'assignation s'effectue sur une liste décrite littéralement ([0,1]). Comme pour tt ses éléments (identiques pour les 2 listes (tt & [0,1])) possède l'id qui a été défini pour 0 & pour 1. Comme pour la liste tt une id est donnée à la liste [0,1]. Et cette id est donc référencée n fois dans la liste a3.

          Mais contrairement à tt cette id est redéfini à chaque réassignation, même si par exemple on réassigne a3 avec la même liste ([0,1]). Et bien évidemment les id de a1 & a3 sont redéfinies à chaque nouvelle assignation.

          Pour b1 l'assignation s'effectue comme pour a3 sur une liste décrite littéralement et comme pour a2  (sous la forme d'une liste en compréhension) dans une boucle for. La liste [0,1] est réévaluée à chaque itération et on obtient donc une id différente pour chaque occurrence de la liste [0,1] contenue dans b1.

          Je me demandais si ces différences de référencement sont liées au fait que les listes sont mutables?

          tt = [0,1]
          print('ID_item tt =', [id(item) for item in tt])
          print('ID tt =', id(tt), '\n')
          
          a1 = [tt]*2
          print('ID_item a1 =', [id(item) for item in a1])
          print('ID_item a1 item =', id(a1[0][0]), id(a1[0][1]), id(a1[1][0]), id(a1[1][1]))
          print('ID a1 =', id(a1), '\n')
          
          print('ID tt =', id(tt), '\n')
          print('--------------------------------------------------------')
          
          a2 = [tt for _ in range(2)]
          print('ID_item a2 =', [id(item) for item in a2])
          print('ID_item a2 item =', id(a2[0][0]), id(a2[0][1]), id(a2[1][0]), id(a2[1][1]))
          print('ID a2 =', id(a2), '\n')
          
          print('ID tt =', id(tt), '\n')
          print('--------------------------------------------------------')
          
          a3 = [[0,1]]*2
          print('ID_item a3 =', [id(item) for item in a3])
          print('ID_item a3 item =', id(a3[0][0]), id(a3[0][1]), id(a3[1][0]), id(a3[1][1]))
          print('ID a3 =', id(a3), '\n')
          print('--------------------------------------------------------')
          
          a1 = [tt]*2
          print('ID_item a1 =', [id(item) for item in a1])
          print('ID_item a1 item =', id(a1[0][0]), id(a1[0][1]), id(a1[1][0]), id(a1[1][1]))
          print('ID a1 =', id(a1), '\n')
          
          a1 = [tt]*2
          print('ID_item a1 =', [id(item) for item in a1])
          print('ID_item a1 item =', id(a1[0][0]), id(a1[0][1]), id(a1[1][0]), id(a1[1][1]))
          print('ID a1 =', id(a1), '\n')
          
          a3 = [[0,1]]*2
          print('ID_item a3 =', [id(item) for item in a3])
          print('ID_item a3 item =', id(a3[0][0]), id(a3[0][1]), id(a3[1][0]), id(a3[1][1]))
          print('ID a3 =', id(a3), '\n')
          
          a3 = [[0,1]]*2
          print('ID_item a3 =', [id(item) for item in a3])
          print('ID_item a3 item =', id(a3[0][0]), id(a3[0][1]), id(a3[1][0]), id(a3[1][1]))
          print('ID a3 =', id(a3), '\n')
          print('--------------------------------------------------------')
          
          b1 = [[0,1] for _ in range(2) ]
          print('ID_item b1 =', [id(item) for item in b1])
          print('ID_item b1 item =', id(b1[0][0]), id(b1[0][1]), id(b1[1][0]), id(b1[1][1]))
          print('ID b1 =', id(b1), '\n')



          • Partager sur Facebook
          • Partager sur Twitter
            26 novembre 2019 à 22:44:46

            La différence n'est pas liée au fait que les objets soient mutables, non. Par contre elle se constate parce qu'ils le sont.

            Les références multiples ne posent jamais de problèmes sur les objets immutables, puisque ces problèmes sont toujours liés aux modifications.

            • Partager sur Facebook
            • Partager sur Twitter
              26 novembre 2019 à 22:49:44

              Effectivement, regarder les id permet de mieux comprendre.

              Endoh a écrit:

              Je me demandais si ces différences de référencement sont liées au fait que les listes sont mutables?




              Tu veux dire si on change juste tt par un immuable comme une chaîne et que le reste a1, a2, a3 est inchangé ?
              • Partager sur Facebook
              • Partager sur Twitter
                27 novembre 2019 à 10:09:16

                Non en fait je m'interrogeais sur les résultats d'id entre tt et [0,1] pour a1, a2, a3 & b1, expression contre forme littérale. Mais a mieux y regarder, le référencement est lié à la gestion de distribution d'id que les objets soient ou non mutables.

                Merci à tous pour cette bonne leçon qui m'a bien fait cogiter.

                entwanne a écrit:

                Les références multiples ne posent jamais de problèmes sur les objets immutables, puisque ces problèmes sont toujours liés aux modifications.

                Je crois que je ne suis pas près de l'oublier. ;)





                • Partager sur Facebook
                • Partager sur Twitter

                Différence d'assignation de liste

                × 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