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 :

Problème avec l'heritage de dict


Sujet :

Python

  1. #1
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2011
    Messages
    136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2011
    Messages : 136
    Points : 89
    Points
    89
    Par défaut Problème avec l'heritage de dict
    Je suis entrain de lire le chapitre sur l'heritage des dictionnaires de Dive into Python : http://python.developpez.com/cours/D...ss_methods.php

    Et ne comprenant pas très bien comment cela cherche j'ai écrit ce bout de code pour essayer de mieux comprendre. Cuisante échec j'ai plein d'erreur que je ne suis pas sur de comprendre donc je m'en remet à vous :

    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class A(dict):
     
        def __init__(self, name=None, genre=None) :
            self["name"] = name
            self.genre=genre
     
    class B(A):
     
        def __init__(self, name=None, genre=None) :
            A.__init__(name, genre)
     
        def __setitem__(self, key, item):
            self.data[key] = item
     
        def __getitem__(self, key):
            return self.data[key]

    Resultat :
    Code console : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    >>> from test_dict_class import A, B
    >>> a = A("rolling stones", "rock")
    >>> a["genre"]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    KeyError: 'genre'
    >>> a.genre
    'rock'
    >>> a["name"]
    'rolling stones'
    >>> a.name
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'A' object has no attribute 'name'

    Je suis étonné qu'il n'y a pas de correspondance entre un attribut de l'objet. Enfin jusque là ça va. C'est ensuite que ça se complique :

    Code console : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> b = B("beatles", "pop")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "test_dict_class.py", line 10, in __init__
        A.__init__(self, name, genre)
      File "test_dict_class.py", line 4, in __init__
        self["name"] = name
      File "test_dict_class.py", line 13, in __setitem__
        self.data[key] = item
    AttributeError: 'B' object has no attribute 'data'

    Pourquoi ligne 4 mon __init__ n'est pas bon ? Pourquoi ligne 6 il n’arrive pas à faire self["name"]=name alors que précédemment il n’y avait aucun problème ? Pourquoi mon objet n'a pas d'attribut data (c'est ce qui est marqué dans le cours) ? (quand je remplace self.data[key] par self[key] c'est encore pire)

  2. #2
    Membre expérimenté
    Profil pro
    Développeur en systèmes embarqués retraité
    Inscrit en
    Mars 2006
    Messages
    946
    Détails du profil
    Informations personnelles :
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2006
    Messages : 946
    Points : 1 351
    Points
    1 351
    Par défaut
    Salut,

    il manquait l'instance à l'appel de A.__init__ ainsi que la déclaration du dictionnaire data. Sinon, je trouve que "drive my car" est beaucoup plus rock que "Angie".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    class A(dict):
     
        def __init__(self, name=None, genre=None) :
            self["name"] = name
            self.genre=genre
     
    class B(A):
     
        def __init__(self, name=None, genre=None) :
            self.data = {}
            A.__init__(self, name, genre)
     
        def __setitem__(self, key, item):
            self.data[key] = item
     
        def __getitem__(self, key):
            return self.data[key]
     
     
    a = A("rolling stones", "rock")
    print a.genre
    b = B("beatles", "pop")
    print b.genre
    A+

    Pfeuh

  3. #3
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Citation Envoyé par ernestrenan Voir le message
    Je suis étonné qu'il n'y a pas de correspondance entre un attribut de l'objet.
    Les attributs de chaque objet sont stockés dans un dictionnaire; ceci est valable pour toutes les classes; ce dictionnaire est accessible par l'attribut __dict__.

    Mais il n'y a pas de correspondance entre les éléments contenu dans un dictionnaire et son propre __dict__ (c'est à dire ses attributs). D'abord ce ne serait pas prudent (si qq'un écrasait la clé "keys" par exemple?), et puis le __dict__ n'admet que des chaînes de caractères comme clés alors qu'un dictionnaire peut contenir d'autres types de clés.

    Il y a moyen de rédéfinir __getattr__ et __setattr__, de le même façon que __getitem__ et __setitem__; tu peux utiliser cela pour implémenter un dict où les éléments seraient aussi accessibles comme attributs, si tu le désires, mais il faudra faire des choix quant à l'écrasement des attibuts existants...

    Citation Envoyé par ernestrenan Voir le message
    Pourquoi ligne 4 mon __init__ n'est pas bon ? Pourquoi ligne 6 il n’arrive pas à faire self["name"]=name alors que précédemment il n’y avait aucun problème ? Pourquoi mon objet n'a pas d'attribut data (c'est ce qui est marqué dans le cours) ? (quand je remplace self.data[key] par self[key] c'est encore pire)
    Dans le lien que tu donnes, il ne s'agit pas de la classe dict mais de UserDict (cf section 5.5), ce sont deux classes différentes. UserDict est obsolète puisque tu peux directement hériter de dict, mais dict n'a pas d'attribut data.

    C'est la seule erreur mentionnée dans le traceback, ce qui est indiqué au-dessus est la pile d'appel ayant mené à l'exception. self["name"] = name a déclenché un appel à __setitem__, mais c'est la version redéfinie de __setitem__ qui est appelée et déclenche l'erreur.

    Utiliser self[key] dans __getitem__ (ou self[key]=... dans __setitem__) pose un problème puisque self[key] va en fait appeler __getitem__, ce qui crée une récursion impropre. Pour éviter cela, dans un héritage, tu peux par exemple décider d'appeler le __getitem__ de la classe parente comme ceci: A.__getitem__(self, key) (ou super(B,self).__getitem__(key)).

  4. #4
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 811
    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 : 3 811
    Points : 7 096
    Points
    7 096
    Par défaut
    On peut utiliser super() aussi

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #!/usr/bin/python
    # -*- coding:utf8 -*-
     
    class A(dict):
     
        def __init__(self, name=None, genre=None) :
            super(A, self).__init__()
            self['name'] = name
            self.genre = genre
     
    class B(A):
     
        def __init__(self, name=None, genre=None) :
            self.data = {}
            super(B, self).__init__(name, genre)
     
        def __setitem__(self, key, item):
            self.data[key] = item
     
        def __getitem__(self, key):
            return self.data[key]
     
    a = A("rolling stones", "rock")
    print a.genre
    b = B("beatles", "pop")
    print b.genre
    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)

  5. #5
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2011
    Messages
    136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2011
    Messages : 136
    Points : 89
    Points
    89
    Par défaut
    Merci j'avais pas bien compris cette histoire de (dict) et (UserDict). En fait les fonction du style __myfunc__ sont un peu comme le méthodes magiques de php qu'on peut surcharger c'est plus clair avec vos explications (je dois dire qu'ils auraient du par moment appeler le tuto "plonger dans python ... mais sans palmes ni bouteilles" ).

    (Sinon pour l’anecdote les bulit in object comme les listes ou les dictionnaires n'ont pas d'attributs __dict__. Donc les dict n'ont pas de __dict__ )

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 281
    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 281
    Points : 36 768
    Points
    36 768
    Par défaut
    Salut,
    Juste pour ajouter de la confusion:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class A(dict):
     
        def __init__(self, name=None, genre=None) :
            super(A, self).__init__(name=name, genre=genre)
        @property
        def genre(self):
            return self["genre"]
        @genre.setter
        def genre(self, v):
            self["genre"] = v
    code pas testé
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Citation Envoyé par ernestrenan Voir le message
    (Sinon pour l’anecdote les bulit in object comme les listes ou les dictionnaires n'ont pas d'attributs __dict__. Donc les dict n'ont pas de __dict__ )
    Bien vu! Cela ne met pas en cause mes remarques mais j'aurais du vérifier. Python manque parfois un peu d'orthogonalité. Les built-ins sont des types comme les autres mais... Et puis ne parlons même pas des __slots__ (je me demande si ceux-ci sont utilisés dans un projet sérieux)...

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 281
    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 281
    Points : 36 768
    Points
    36 768
    Par défaut
    Salut,

    Une classe avec __slots__ n'a pas de __dict__.
    Sinon on peut ajouter un __dict__ au dict et obtenir aussi l'effet recherché attribut <=> clef du dict

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class A(dict):
     
        def __init__(self, name=None, genre=None) :
            super(A, self).__init__(name=name, genre=genre)
            self.__dict__ = self #
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. Problème avec l'heritage virtuel
    Par Spandelles dans le forum Débuter
    Réponses: 4
    Dernier message: 05/12/2008, 10h40
  2. problème avec heritage en java
    Par yLaplace dans le forum Langage
    Réponses: 16
    Dernier message: 27/03/2007, 12h31
  3. Problème avec le type 'Corba::Any_out'
    Par Steven dans le forum CORBA
    Réponses: 2
    Dernier message: 14/07/2002, 18h48
  4. Problème avec la mémoire virtuelle
    Par Anonymous dans le forum CORBA
    Réponses: 13
    Dernier message: 16/04/2002, 16h10

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