IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Affectation de variable


Sujet :

Python

  1. #1
    Invité
    Invité(e)
    Par défaut Affectation de variable
    Bonjour,

    Entre :
    &
    Quelle affectation est la plus optimale?

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 589
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 589
    Par défaut
    Salut,

    Citation Envoyé par MissLoop Voir le message
    Quelle affectation est la plus optimale?
    Quand vous écrivez a = machin, l'assignation/affectation de l'objet machin à a n'a aucune raison de dépendre de la nature de l'objet machin.

    Par contre la différence entre [0, 0], liste sous forme littérale contenant deux zéros, et [0]*2 qui fabrique une liste semblable à partir d'une liste réduite à 1 seul zéro saute au yeux: il suffit de regarder les opérations effectuées.

    L'affectation coûte la même chose, la création/construction de l'objet à assigner, c'est autre chose. Ici, s'il y a une différence, elle sera "epsilonnesque" et n'aura d'importance que si l'opération sera répétée plusieurs millions de fois.

    Maintenant, vous vous rendez aussi compte que fabriquer une liste à N éléments nuls sera possible avec [0]*N alors que sans connaitre N, impossible d'écrire çà sous forme littérale.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Notez que l'affectation
    est très dangereuse (et souvent ce n'est pas ce qu'on veut) si A n'est pas 0 comme dans votre exemple, mais plutôt un objet, ou plus généralement un mutable (une liste par exemple). Dans ces cas là, si on ne connait pas N à l'avance on devra instancier comme ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    a = [A for _ in range(N)]

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 589
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 589
    Par défaut
    Citation Envoyé par lg_53 Voir le message
    si A n'est pas 0 comme dans votre exemple, mais plutôt un objet, ou plus généralement un mutable (une liste par exemple). Dans ces cas là, si on ne connait pas N à l'avance on devra instancier comme ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    a = [A for _ in range(N)]
    suivit de:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    a = [ A for _ in range(N)]
    produira le même résultat que:
    car j'assigne dans les 2 cas N fois la référence au même objet A.

    Et çà n'a rien à voir avec:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    a = [ [] for _ in range(N)]
    est identique à
    dans le premier cas, je crée un objet liste vide [] à chaque itération alors que dans le 2nd je le recopie N fois.
    Subtil?

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Effectivement, j'ai écrit comme cela (avec A) pour avoir une écriture plus compact, mais ca peut prêter à confusion.
    Donc pour être clair, oui, dans ce que j'ai écrit il faut bien comprendre (pour l'exemple disons que A vaut [1,2,3]):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    a = [ [1,2,3] for _ in range(N)]
    .vs.
    (qui produisent des résultats différents)

    et non pas

    puis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    a = [ A for _ in range(N)]
    .vs.
    qui là en effet produisent la même chose.

  6. #6
    Invité
    Invité(e)
    Par défaut
    Donc si je récapitule:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    tt = [0,1]
    n =2
    a = [tt for _ in range(n)]
    b = [tt] * n
    IDEM : À a & b est assignées 2 fois la référence de tt, soit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    [[0, 1], [0, 1]]
    [[0, 1], [0, 1]]
    Pour:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    c = [[0,1] for _ in range(n)]
    d = [[0,1]] * n
    IDENTIQUE : c est construit par la référence de tt à chaque itération alors que la référence de tt est copié dans d 2 fois, soit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    [[0, 1], [0, 1]]
    [[0, 1], [0, 1]]
    Même procédé que pour c & d mais avec un résultat différent:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    e = [[tt] for _ in range(n)]
    f = [[tt]] * n
    Soit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    [[[0, 1]], [[0, 1]]]
    [[[0, 1]], [[0, 1]]]
    Ai-je bien compris?

  7. #7
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Citation Envoyé par MissLoop Voir le message
    Ai-je bien compris?

    Non, je crois bien que vous ayez compris à l'envers !

    Exécutez ces codes, et observer attentivement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    tt = [0,1]
    n =2
    a = [tt for _ in range(n)]
    print(a)
    a[0][0] = 17
    print(a)
    print(tt)
    tt[1]=100
    print(a)
    print(tt)
    puis celui ci, qui donneras le meme résultat

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    tt = [0,1]
    n =2
    a = [tt]*n
    print(a)
    a[0][0] = 17
    print(a)
    print(tt)
    tt[1]=100
    print(a)
    print(tt)
    Finalement externalisé tt n'a pas vraiment d'importance puisque le code suivant produit le même comportement

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    n =2
    a = [[0,1]]*n
    print(a)
    a[0][0] = 17
    print(a)
    Mais ce dernier code, qui ne fait pas de modification collatérale, lui est différent, et est en général ce que l'on veut faire contrairement à tous les codes précédents

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    n =2
    a = [[0,1] for _ in range(n) ]
    print(a)
    a[0][0] = 17
    print(a)
    Je vous laisse observez ce qui se passe lorsque vous éxécutez tout cela.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    n =2
    a = [[0,1] for _ in range(n) ]
    print(a)
    a[0][0] = 17
    print(a)

  8. #8
    Invité
    Invité(e)
    Par défaut
    Ok, je pense que j'ai saisi.
    pour :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    n =2
    a = [[0,1] for _ in range(n) ]
    print(a)
    a[0][0] = 17
    print(a)
    a est construit à chaque itération.
    Ce qui implique qu'à la première itération à l'indice 0 de a et à l'indice 0 de l'objet contenu dans a sera assigné 17 soit [17,1]. À la seconde itération comme aucune autre instruction est donnée, l'objet est construit dans sa valeur initiale soit [0,1]. On a donc:
    Pour tous les autres blocs de code l'objet contenu dans a est copié n fois.
    Ce qui implique que si on assigne une nouvelle valeur à l'indice 0 de a et à l'indice 0 de l'objet contenu dans a on change la valeur de référence. On aura donc:
    Merci beaucoup a vous deux pour cette excellente leçon

    Ceci étant,
    Notez que l'affectation
    Code :

    a = [A]*N

    est très dangereuse
    Pourquoi cette affectation est très dangereuse?

  9. #9
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 769
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 769
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par MissLoop Voir le message
    Pourquoi cette affectation est très dangereuse?
    Ce n'est pas l'affectation en elle-même qui est dangereuse mais, et vous l'avez bien compris, que le résultat dépend de la nature de "A".
    Si "A" est un simple int/double ça ira mais si "A" est un truc plus complexe et surtout mutable (liste, dico) alors il est simplement référencé N fois.
    Et ensuite modifier a[0] reviendra à modifier une unique référence ce qui se répercute alors dans tous les a[x].

    Et donc ce code suivant
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    a=[[0,]] * 5
    print(a)
    a[2][0]=18
    print(a)
    produira le résultat suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    [[0], [0], [0], [0], [0]]
    [[18], [18], [18], [18], [18]]
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  10. #10
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Citation Envoyé par MissLoop Voir le message
    a est construit à chaque itération
    Non. C'est 2 lignes là :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    a=[[0,1] ] * 5
    b=[[0,1] for _ in range(5) ]
    construisent chacune une liste.

    Faire ca ensuite
    ce n'est pas faire une 2eme itération dans la construction de votre liste. Non la liste est déjà créée. Faire ca, c'est assigner une nouvelle valeur a un élément de la liste (élément d'une sous liste pour être plus précis).

    Citation Envoyé par MissLoop Voir le message
    Pour tous les autres blocs de code l'objet contenu dans a est copié n fois.
    En fait non.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    b=[[0,1] for _ in range(5) ]
    ici [0,1] est littéralement copié 5 fois, et vous obtenez à la fin 5 copies indépendantes
    ici [0,1] n'est créé qu'une seul fois, et on met 5 références vers cette même liste. Ce qui explique pourquoi si vous en modifiez un, il sont tous modifié: il pointe tous sur la même liste d'origine.

  11. #11
    Invité
    Invité(e)
    Par défaut
    Merci à vous trois pour votre patience.

    D'accord... donc,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    tt = [0,1]
    a1 = [[0,1]]*5
    a2 = [tt for _ in range(5)]
    a3 = [tt]*5
    avec en test,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    a1[2][0]=18
    a2[2][0]=18
    a3[2][0]=18
    ici [0,1] & tt sont créés 1 seule fois chacun pour 5 références vers 1 liste.
    Conséquence : la modification d'une seule référence entraîne la modification de toutes les autres car elles pointent toutes vers la même liste d'origine.
    Cette liste d'origine étant [0,1] & tt selon l'exemple.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    b1 = [[0,1] for _ in range(5)]
    b2 = [0,1]*5
    avec en test,

    ici [0,1] est copié 5 fois chacun pour 5 copies indépendantes dans 1 liste.

    Ok, mais je suis incapable de lire une différence entre les assignations des a et des b même si je suis prête à admettre ces explications. Entre a2 et b1 par exemple il n'y a rien qui me saute aux yeux et encore moins entre a1 et b2, comment faites-vous pour voir ces différences?

  12. #12
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 589
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 589
    Par défaut
    Citation Envoyé par MissLoop Voir le message
    Entre a2 et b1 par exemple il n'y a rien qui me saute aux yeux et encore moins entre a1 et b2, comment faites-vous pour voir ces différences?
    On s'est déjà fait avoir assez souvent pour déceler ces différences et on a appris a y mettre des mots dessus:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    tt = [0,1]
    a2 = [tt for _ in range(5)]
    Ici vous voyez (ou pas) qu'on crée 5 fois une référence au même objet que celui assigné à tt.

    Par contre ici:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    b1 = [[0,1] for _ in range(5)]
    La variable a été remplacé par l'expression littérale [0, 1] qui dit crée une liste avec les nombres 0 et 1 dedans. Répété 5 fois, on aura 5 objets égaux mais différents.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  13. #13
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 769
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 769
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par MissLoop Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    b1 = [[0,1] for _ in range(5)]
    b2 = [0,1]*5
    Attention à la syntaxe. Je présume que tu veux rendre b2 similaire à b1 pour tes tests. Or [0,1]*5 va copier 5 fois d'affilée la suite "0, 1" dans un simple tableau => b2=[0, 1, 0, 1, 0, 1, 0, 1, 0, 1] et ne correspondra absolument pas à b1 qui, lui, est un vrai tableau 2D.
    Pour rendre b2 similaire à b1 il faut écrire b2=[[0, 1],]*5 indiquant qu'on veut créer un tableau contenant 5 fois le couple [0, 1]. Et la virgule avant le dernier crochet n'est pas obligatoire pour une liste mais l'est pour un tuple (ce n'est pas la parenthèse qui fait le tuple mais la virgule ainsi (0) est un simple int tandis que (0,) est lui un vrai tuple) donc perso je la mets tout le temps pour rester cohérent dans ma syntaxe.

    Citation Envoyé par MissLoop Voir le message
    comment faites-vous pour voir ces différences?
    Ben déjà on sait (et c'est bien ancré) que répéter un truc complexe c'est super dangereux donc quand on se lance, on fait super gaffe. Ensuite si on se trompe malgré tout, le programme part en cacahouette dès le premier test, donc on met un print() et on voit immédiatement qu'on s'est gauffrés. Et puis bon, ce n'est pas non plus une syntaxe dont on a besoin tous les 4 matins...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

Discussions similaires

  1. Problème d'affectation de variable
    Par bob33 dans le forum C
    Réponses: 3
    Dernier message: 04/11/2005, 18h01
  2. Affecter une variable javascript à une variable php
    Par gwendy dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 17/10/2005, 21h58
  3. affecter une variable de type stringstream
    Par sorari dans le forum SL & STL
    Réponses: 3
    Dernier message: 24/03/2005, 12h14
  4. [PS] affectation de variable
    Par madmortal dans le forum SQL
    Réponses: 2
    Dernier message: 01/09/2004, 14h17
  5. script SQL : affectation de variables
    Par Laura dans le forum Requêtes
    Réponses: 3
    Dernier message: 28/10/2003, 22h32

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo