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 :

court circuiter __getitem__ par attribut


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Par défaut court circuiter __getitem__ par attribut
    Bonjour,

    Lorsque l'on assigne un attribut ayant le même nom qu'une méthode, celui ci prends la priorité sur cette dernière. Est ce normal si cela ne fonctionne pas pour l'attribut __getitem__, accédé avec la syntaxe d[] ? (Je suis en Py25)

    Merci d'avance

    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):
            dict.__init__(self)
        def __getitem__(self, k):
            print "A.get ",k
            return dict.__getitem__(self, k)
     
    class D(A):
        def __init__(self):
            A.__init__(self)
            self._inner= dict()
            "Shortcuts __getattr__ to self._inner"
            self.__getattr__= self._inner.__getitem__
     
    if __name__ == '__main__':
        d=D()
        d._inner[0]= 1 
        d[0]= 1
        print "d.__getattr__(0)"
        d.__getattr__(0) # does not call A.__getitem__, as expected
        print "d[0]"
        d[0] # this CALLS A.__getitem__, UNEXPECTED !

  2. #2
    Membre Expert

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Par défaut
    M’enfin, d._inner est un objet dict normal, pas un objet A*! Donc quand tu fais d.__getattr__(0) tu appelles la méthode __getitem__() de dict, pas de A.

    Par contre, puisque D hérite de A, quand tu appelles directement le __getitem__ de D (via le raccourci syntaxique d[0]), puisque D n’en a pas, python recherche dans la hiérarchie d’héritage, et trouve le __getitem__ de A.

    À noter, je ne crois pas (à vérifier) qu’il soit possible d’obtenir la “partie parent” d’un objet, comme c’est le cas en C++ (et même en C, dans une certaine mesure) avec le système de cast de pointeurs… Je me trompe peut-être, mais j’ai bien l’impression que c’est ce que tu essayes de faire avec _inner*?

  3. #3
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 062
    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 062
    Par défaut
    J'ai du mal à comprendre le but, mais

    Lorsque l'on assigne un attribut ayant le même nom qu'une méthode
    Pour assigner un attribut, on utilise __setattr__()

    Sinon

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    self.__getattr__= self._inner.__getitem__
    Bizarre, syntaxiquement il y a pas d'erreur?

    J'aurais plutôt fais un truc du genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    def __getattr__(self, attr):
        if attr in self._inner:
            return self.__getitem__(attr)
    Tu as un exemple d'application, car la théorie et moi ça fait 2

  4. #4
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Bonjour,

    En fait je pense que VV33D parle de ceci:
    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
    27
    class A(dict):
        def __init__(self):
            dict.__init__(self)
     
        def __getitem__(self, k):
            print "A.__getitem__", k
            return dict.__getitem__(self, k)
     
     
    class D(A):
        def __init__(self):
            A.__init__(self)
            self._inner = dict()
            self.__setitem__ = self._inner.__setitem__
            self.__getitem__ = self._inner.__getitem__
            self.__delitem__ = self._inner.__delitem__
     
     
        def getinner(self):
            return self._inner
     
     
    if __name__ == '__main__':
        d = D()
        d[0] = 1
        print "d[0]", d[0]
        print d.getinner()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    d[0] A.__getitem__ 0
    1
    {}
    Par rapport à la surcharge suivante:
    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
    27
    28
    29
    30
    31
    32
    class A(dict):
        def __init__(self):
            dict.__init__(self)
     
        def __getitem__(self, k):
            print "A.__getitem__", k
            return dict.__getitem__(self, k)
     
     
    class D(A):
        def __init__(self):
            A.__init__(self)
            self._inner = dict()
     
        def __setitem__(self, k, v):
            self._inner[k] = v
     
        def __getitem__(self, k):
            return self._inner[k]
     
        def __delitem__(self, k):
            del self._inner[k]
     
        def getinner(self):
            return self._inner
     
     
    if __name__ == '__main__':
        d = D()
        d[0] = 1
        print "d[0]", d[0]
        print d.getinner()
    Que l'on pourrais écrire:
    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
    27
    class A(dict):
        def __init__(self):
            dict.__init__(self)
     
        def __getitem__(self, k):
            print "A.__getitem__", k
            return dict.__getitem__(self, k)
     
     
    class D(A):
        def __init__(self):
            A.__init__(self)
            self._inner = dict()
     
        __setitem__ = lambda self, k, v:  self._inner.__setitem__(k, v)
        __getitem__ = lambda self, k: self._inner.__getitem__(k)
        __delitem__ = lambda self, k: self._inner.__delitem__(k)
     
        def getinner(self):
            return self._inner
     
     
    if __name__ == '__main__':
        d = D()
        d[0] = 1
        print "d[0]", d[0]
        print d.getinner()
    Ou, suivant les besoins:
    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
    27
    28
    29
    class A(dict):
        def __init__(self):
            dict.__init__(self)
     
        def __getitem__(self, k):
            print "A.__getitem__", k
            return dict.__getitem__(self, k)
     
     
    class D(A):
     
        INNER = dict()
     
        def __init__(self):
            A.__init__(self)
     
        __setitem__ = INNER.__setitem__
        __getitem__ = INNER.__getitem__
        __delitem__ = INNER.__delitem__
     
        def getinner(self):
            return self.INNER
     
     
    if __name__ == '__main__':
        d = D()
        d[0] = 1
        print "d[0]", d[0]
        print d.getinner()
    Mais je n'ai peut être pas compris la question.

    @+

  5. #5
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    J'allais oublier:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class D(A):
        def __init__(self):
            A.__init__(self)
            self._inner = dict()
            self.__class__.__getitem__ = self._inner.__getitem__
            self.__class__.__setitem__ = self._inner.__setitem__
    @+

  6. #6
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Par défaut
    Merci à tous pour vos réponses,

    Je repars du code de PauseKawa et je récapitule :
    Quand je fais d.__getitem__(0), python vérifie dans self.__dict__ la présence de __getitem__, avant d'aller voir dans les classes, ce qui est le comportement attendu.

    Par contre, d[0] ne vérifie pas dans self.__dict__ et utilise directement le __getitem__ renvoyé par la hiérarchie de classes. C'est bien ce comportement qui me choque. Pourquoi diable est ce que Python n'utilise pas
    getattr(self,'__getitem__') ? (Du coup j'imagine qu'il en va de même pour les autres opérateurs)

    En ce qui concerne les alternatives proposées par PauseKawa, aucune ne me satisfait car
    * La première (avec lambdas) me fait perdre la vitesse builtin de dict.__getitem__ (même si dans l'idée, elle fait ce que je voudrais).
    * La seconde suppose que inner est un état partagé par toutes les instances de D

    En ce qui concerne les autres remarques
    @fred1599: désolé pour l'erreur, je voulais effectivement écrire self.__getitem__ = self._inner.__getitem__
    Pour assigner un attribut, on utilise __setattr__()
    -> self.__getitem__ = ... marche aussi

    ce que tu essayes de faire avec _inner
    J'essaye juste de 'surcharger' une méthode sur une instance particulière (bon ici c'est fait dans le constructeur donc ça affectera toutes les instances de D) . Et j'obtiens bien le comportement souhaité avec la syntaxe d.__getitem__(0), mais pas avec d[0]

  7. #7
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    C'est bien cela : [] fait directement appel à la méthode de classe.
    La dernière proposition devrais plus vous convenir (self.__class__).

  8. #8
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 062
    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 062
    Par défaut
    J'essaye juste de 'surcharger' une méthode sur une instance particulière
    Désolé je ne comprend pas, une surcharge opérateur sur une instance?

    Là j’apprends quelque-chose, je veux bien qu'on m'explique.

    Il ne serait pas possible en terme d'objet de donner un exemple d'utilisation de ce que tu souhaites faire, j'ai vraiment du mal à cerner le problème qui me semble intéressant, ce serait dommage de passer à côté.

  9. #9
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Bonsoir,

    Ceci dit:

    Citation Envoyé par VV33D Voir le message
    * La première (avec lambdas) me fait perdre la vitesse builtin de dict.__getitem__
    Vu la taille du bloc et la closure de lambda je ne pense pas que cela soit si énorme... A tester sur sur une longue itération/des itérations multiples.
    Ce ne sera sans doute pas au même niveau mais la question se pose sur le besoin de 'vitesse'.

    type propose une flexibilité via le dico. C'est énorme pour construire de multiples instances 'personnalisées'.

    @+

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

Discussions similaires

  1. [PageControl] Raccourcis claviers court-circuités
    Par Manopower dans le forum Composants VCL
    Réponses: 8
    Dernier message: 04/09/2009, 16h52
  2. Réponses: 2
    Dernier message: 06/07/2007, 10h41
  3. Réponses: 13
    Dernier message: 09/04/2007, 13h20
  4. [XSLT]Regroupement par attribut.
    Par zserdtfg dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 08/12/2006, 11h35
  5. Réponses: 4
    Dernier message: 16/03/2004, 18h03

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