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 :

Les dictionnaires en compréhension ne marchent pas pour les sous-dictionnaires [Python 3.X]


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 853
    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 853
    Billets dans le blog
    1
    Par défaut Les dictionnaires en compréhension ne marchent pas pour les sous-dictionnaires
    Bonjour
    Je viens de remarquer que dans un dictionnaire en compréhension, on ne peut pas utiliser une variable définie dans un sous-dictionnaire dans le dictionnaire "parent".

    Exemple: je crée un dictionnaire où chaque clé sera associée à un tuple de sa valeur
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    dd={k : tuple(range(k+1)) for k in range(1, 6)}
    print(dd)		# {1: (0, 1), 2: (0, 1, 2), 3: (0, 1, 2, 3), 4: (0, 1, 2, 3, 4), 5: (0, 1, 2, 3, 4, 5)}
    Jusque là, pas de problème.

    Mais si je cherche à déplacer chaque tuple dans un sous-dictionnaire...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    dd={k : {"data" : tuple(range(k+1)) for k in range(1, 6)}}
    print(dd)
    ...là où je m'attendais à avoir {1: {"data" : (0, 1)}, 2: {"data" : (0, 1, 2)}, 3: {"data" : (0, 1, 2, 3)}, 4: {"data" : (0, 1, 2, 3, 4)}, 5: {"data" : (0, 1, 2, 3, 4, 5)}} j'ai eu un NameError: name 'k' is not defined.

    Effectivement avec le recul c'est compréhensible. Le sous-dictionnaire étant probablement généré à part, la variable "k" ne remonte pas sur le parent. Mais sur le coup j'ai été un peu surpris.

    PS : en fait, même pas besoin de sous-dictionnaire. Une simple superposition de cast suffit à reproduire le souci.
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    d1={k : tuple(range(k+1)) for k in range(1, 6)}			# ok
    d2={k : tuple(tuple(range(k+1)) for k in range(1, 6))}		# Erreur
    Si quelqu'un a un avis...
    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]

  2. #2
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 152
    Par défaut
    Hello,

    Dans ton code qui ne fonctionne pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    dd={k : {"data" : tuple(range(k+1)) for k in range(1, 6)}}
    L'interpréteur voit en réalité deux compréhensions distinctes et imbriquées:


    1. La compréhension "externe" : {k : ... for k in range(1, 6)}
    2. La compréhension "interne" : {"data" : tuple(range(k+1)) for k in range(1, 6)}


    La compréhension interne crée sa propre "bulle" (sa propre portée). Quand elle essaie d'accéder à k pour faire range(k+1), elle regarde dans sa bulle, ne le trouve pas, et ne va pas chercher dans la bulle "sœur" de la compréhension externe. D'où le NameError !

    Pour obtenir le résultat que tu veux, il ne faut en réalité créer qu'une seule et unique compréhension.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    dd = {k: {"data": tuple(range(k+1))} for k in range(1, 6)}
    Citation Envoyé par interpréteur
    In [1]: dd = {k: {"data": tuple(range(k+1))} for k in range(1, 6)}


    In [2]: dd
    Out[2]:
    {1: {'data': (0, 1)},
    2: {'data': (0, 1, 2)},
    3: {'data': (0, 1, 2, 3)},
    4: {'data': (0, 1, 2, 3, 4)},
    5: {'data': (0, 1, 2, 3, 4, 5)}}
    L'expression {"data": tuple(range(k+1))} n'est pas une compréhension de dictionnaire (il n'y a pas de for à l'intérieur). C'est ce qu'on appelle un littéral de dictionnaire.

    Je pense que ta source d'erreur est le fait d'avoir déjà fait du python 2.x
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  3. #3
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 853
    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 853
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par fred1599 Voir le message
    Pour obtenir le résultat que tu veux, il ne faut en réalité créer qu'une seule et unique compréhension.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    dd = {k: {"data": tuple(range(k+1))} for k in range(1, 6)}
    Joli
    Effectivement mettre la compréhension dans le dictionnaire "parent" la rend visible de l'enfant.

    Citation Envoyé par fred1599 Voir le message
    La compréhension interne crée sa propre "bulle" (sa propre portée).
    Oui c'est en effet ce que j'ai compris après coup, comme je l'ai dit. Après il y a aussi l'histoire du double tuple de mon PS pour lequel j'ai encore du mal à voir comment ça se raccorde avec le reste de l'histoire mais bon, c'est pas super important (je fais rarement du tuple de tuple)

    Citation Envoyé par fred1599 Voir le message
    Je pense que ta source d'erreur est le fait d'avoir déjà fait du python 2.x
    Oui c'est probable. Merci de ton aide
    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]

  4. #4
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 152
    Par défaut
    Hello

    Pour le tuple c'est même tarif,

    1. Il y a une compréhension de dictionnaire externe : {k: ... for k in range(1, 6)}. Elle définit une variable k dans sa bulle.
    2. À l'intérieur, pour la valeur, il y a un générateur interne : (... for k in range(1, 6)). Ça crée une autre variable k qui n'existe que dans sa propre bulle.


    ----

    Pourquoi je dis que ça peut venir de python 2.x ? C'est tout simplement parce-que cette fuite de variable existait... Guido van Rossum a lui-même qualifié ce comportement d'artefact d'implémentation et de "vilain petit secret" de Python

    Source

    Pour exemple simple,

    En python 2.7

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    fred@FredDebian:~$ python2
     Python 2.7.18 (default, Mar  9 2025, 16:24:14) 
    [GCC 12.2.0] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> x = 'avant'
    >>> a = [x for x in range(3)]
    >>> print x
    2
    Ça aurait dû afficher 'avant' !
    Ce comportement était une source de bogues subtils, car il pouvait écraser involontairement des variables existantes dans la portée englobante. Ceci a été corrigé dans la version 3.

    En python 3.13

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    fred@FredDebian:~$ python3.13
    Python 3.13.5 (main, Jun 25 2025, 18:55:22) [GCC 14.2.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> x = 'avant'
    >>> a = [x for x in range(3)]
    >>> print(x)
    avant
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [eZ Publish] CSS et JS ne marchent pas pour le back-office
    Par V4Vendetta dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 2
    Dernier message: 02/04/2012, 10h01
  2. Ma requête ne calcul pas pour tout les champs
    Par leloup84 dans le forum Requêtes
    Réponses: 10
    Dernier message: 01/03/2006, 12h59
  3. Ma requête ne calcul pas pour tout les champs
    Par leloup84 dans le forum Langage SQL
    Réponses: 2
    Dernier message: 01/03/2006, 10h11
  4. [Performance] - Blob ou pas pour les images d'un site ?
    Par ShinJava dans le forum SQL Procédural
    Réponses: 2
    Dernier message: 04/07/2005, 17h32
  5. [VB.NET] Les évènements ne marchent pas
    Par Dnx dans le forum ASP.NET
    Réponses: 6
    Dernier message: 28/01/2005, 12h54

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