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

  1. #1
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    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 éprouvé

    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
    Points : 1 273
    Points
    1 273
    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 éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 823
    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 823
    Points : 7 119
    Points
    7 119
    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
    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)

  4. #4
    Expert confirmé 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
    Points : 4 005
    Points
    4 005
    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.

    @+
    Merci d'utiliser le forum pour les questions techniques.

  5. #5
    Expert confirmé 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
    Points : 4 005
    Points
    4 005
    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__
    @+
    Merci d'utiliser le forum pour les questions techniques.

  6. #6
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    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
    Expert confirmé 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
    Points : 4 005
    Points
    4 005
    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__).
    Merci d'utiliser le forum pour les questions techniques.

  8. #8
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 823
    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 823
    Points : 7 119
    Points
    7 119
    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é.
    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)

  9. #9
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut
    @fred: une solution limitée pour surcharger une méthode sur une instance seulement consiste à définir un attribut avec le même nom. Par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class A:
        def foo(self): return 1
    b= A()
    a= A()
    a.foo= lambda:2 # foo est "surchargée" pour l'instance a seulement
    Bien sur cette approche a quelques limites:
    * Faire attention si on veut que a.foo dépende de l'etat de self
    * Cela casse la MRO attendue si l'on dérive la classe A (i.e c'est a.foo qui sera appelé, et non classe_dérivée_de_A.foo)
    * Ne marche pas avec __getitem__ dans la syntaxe a[key] !!!

  10. #10
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut
    @PauseKawa: je n'avais pas pensé à cette approche, mais il me semble que
    le comportement est partagé par toutes les instances :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    d= D() # d.__getitem__ pointe vers d._inner
    dd= D()
    # dd.__getitem__ pointe vers dd._inner, mais maintenant d.__getitem__ aussi non ?

  11. #11
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 823
    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 823
    Points : 7 119
    Points
    7 119
    Par défaut
    Ah ben voilà, j'ai compris, je peux enfin réfléchir sur le sujet
    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)

  12. #12
    Expert confirmé 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
    Points : 4 005
    Points
    4 005
    Par défaut
    Donc vous voulez une surcharge juste pour une instance ? Comme 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
    28
    29
    30
    class A(dict):
        def __init__(self):
            dict.__init__(self)
     
        def __getitem__(self, k):
            print "A.__getitem__", k
            return dict.__getitem__(self, k)
     
     
    class B(A):
        def __init__(self):
            A.__init__(self)
     
        def getinner(self):
            return self._inner
     
     
    class Dummy:
        def __init__(self):
            self._inner = dict()
            self.__class__.__getitem__ = self._inner.__getitem__
            self.__class__.__setitem__ = self._inner.__setitem__
            self.__class__.__delitem__ = self._inner.__delitem__
     
     
    if __name__ == '__main__':
        b = type('Justme', (Dummy, B), {})()
        b[0] = 1
        print "b[0]", b[0]
        print b.getinner()
    ...
    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
    class A(dict):
        def __init__(self):
            dict.__init__(self)
     
        def __getitem__(self, k):
            print "A.__getitem__", k
            return dict.__getitem__(self, k)
     
     
    class B(A):
        def __init__(self):
            A.__init__(self)
     
     
    class Dummy:
        def __init__(self):
            self.__class__.__getitem__ = self._inner.__getitem__
            self.__class__.__setitem__ = self._inner.__setitem__
            self.__class__.__delitem__ = self._inner.__delitem__
     
     
    if __name__ == '__main__':
        b = type('Justme', (Dummy, B), {'_inner': dict(), 'getinner': lambda self : self._inner})()
        b[0] = 1
        print "b[0]", b[0]
        print b.getinner()
    Etc...
    Merci d'utiliser le forum pour les questions techniques.

  13. #13
    Expert confirmé 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
    Points : 4 005
    Points
    4 005
    Par défaut
    Et un dernier avec type
    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
    class A(dict):
        def __init__(self):
            dict.__init__(self)
     
        def __getitem__(self, k):
            print "A.__getitem__", k
            return dict.__getitem__(self, k)
     
     
    class B(A):
        def __init__(self):
            A.__init__(self)
     
     
    if __name__ == '__main__':
        b = type('_', (B,), {'_inner': dict(), 'getinner': lambda self : self._inner,
                            '__getitem__': lambda self, k: self._inner.__getitem__(k),
                            '__setitem__': lambda self, k, v : self._inner.__setitem__(k, v),
                            '__delitem__': lambda self, k : self._inner.__delitem__(k)})()
        b[0] = 1
        print "b[0]", b[0]
        print b.getinner()
        c = B()
        c[0] = 1
        print "c[0]", c[0]
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    b[0] 1
    {0: 1}
    c[0] A.__getitem__ 0
    1
    Merci d'utiliser le forum pour les questions techniques.

  14. #14
    Expert confirmé 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
    Points : 4 005
    Points
    4 005
    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'.

    @+
    Merci d'utiliser le forum pour les questions techniques.

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

    Au cas où, cela est documenté ici.

    J'ai compris que c'était une histoire de clou qu'on essaie de faire entrer là où çà ne veut pas... Pourquoi insister? Une colle pourrait très bien faire l'affaire!
    D'autant que Python est assez fourni côté "collages".
    Mais, désolé, je n'ai pas compris le cas d'utilisation i.e. le lien qu'on cherche à construire entre B, A et le dict...
    Bon courage
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  16. #16
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 823
    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 823
    Points : 7 119
    Points
    7 119
    Par défaut
    Mais, désolé, je n'ai pas compris le cas d'utilisation i.e. le lien qu'on cherche à construire entre B, A et le dict...
    Si j'ai bien compris l'objectif est de faire vérifier que le nom de l'attribut d'un objet n'est pas le même nom qu'une méthode de l'objet.

    Dans le cas où le nom de l'attribut est équivalent au nom de la méthode de l'objet, il faut éviter l'assignation, sinon, l'assignation a lieu.

    Je ferais quelque-chose de très simple du genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class A:
        def foo(self):
            return 1
        def __setattr__(self, attr, value):
            if attr in dir(self):
                raise ValueError
            else:
                self.__dict__[attr] = value
    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)

  17. #17
    Expert confirmé 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
    Points : 4 005
    Points
    4 005
    Par défaut
    Bonjour fred1599,

    C'est justement le fait qu'avec [] __dict__ n'est pas utilisé qui gène VV33D:
    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
    class A(dict):
        def __init__(self):
            dict.__init__(self)
     
        def __getitem__(self, k):
            print "A.__getitem__", k
            return dict.__getitem__(self, k)
     
     
    class B(A):
        def __init__(self):
            A.__init__(self)
            self._inner = dict()
            self.__dict__['__getitem__'] = self._inner.__getitem__
            self.__dict__['__setitem__'] = self._inner.__setitem__
     
     
    if __name__ == '__main__':
        b = B()
        b[0] = 1
        print "b[0]", b[0]
    @+
    Merci d'utiliser le forum pour les questions techniques.

  18. #18
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut
    Bonjour,

    Merci pour ces remarques.
    x[i] is roughly equivalent to type(x).__getitem__(x, i)
    Pourquoi est ce que type(x).__getitem__(x, i) revient à chercher i d'abord dans les classes, puis dans l'instance. Ou puis-je trouver de la doc sur la fonction type() svp?
    En effet, si les classes ne définissent pas de getitem, mais que l'instance le fait, c'est l'attribut d'instance qui sera utilisé (cf classe DD ci dessous)
    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
    33
    34
    35
    36
    37
     
    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 __getitem__ to self._inner"
            self.__getitem__= self._inner.__getitem__
            self.__setitem__= self._inner.__setitem__
     
    class DD():
        def __init__(self):       
            self._inner= dict()        
            self.__getitem__= self._inner.__getitem__
            self.__setitem__= self._inner.__setitem__    
     
    if __name__ == '__main__':
        d=D()
        dd=DD()
        d._inner[0]= 1 
        d[0]= 1
        dd._inner[0]= 1 
        dd[0]= 1
        print "d[0]"
        d[0] # CALLS __getitem__, UNEXPECTED !
        print "d.__getattr__(0)"
        d.__getitem__(0) # does not call __getitem__, as expected
        print "="*20
        print "dd[0]"
        dd[0] # does not call __getitem__, as expected
        print "dd.__getattr__(0)"
        dd.__getitem__(0) # does not call __getitem__, as expected
    @wiztricks: il n'y a pas vraiment de cas d'utilisation. Disons que je veux court-circuiter dans D les appels à A.__getitem__, pour des pb de performances (donc avec une simple buitin). Je devrais sans doute plutôt refaire ma hiérarchie de classe !

    @PauseKawa: je fais beaucoup plus d'accès particuliers (d[key]) que d'itérations sur d. Du coup, je pense que le lambda me fait vraiment perdre du temps (car l'appel qu'il wrappe est court) .Par contre faut vraiment que je me mette à type(), merci pour les exemples

  19. #19
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut et un cas qui fait planter
    Si on dérive d'object et de la classe qui particularise la méthode dans le constructeur, on obtient une jolie
    TypeError: 'xD' object does not support item assignment
    J'en conclus que type() se comporte très différemment quand on dérive d'object, mais ça ma laisse perplexe quand même. Pourquoi Python a-t'il besoin de faire type(x).__getitem__(x, i) , plutôt que getattr(x,'__getitem__')(i) ???

    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    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 __getitem__ to self._inner"
            self.__getitem__= self._inner.__getitem__
            self.__setitem__= self._inner.__setitem__
     
    class DD:
        def __init__(self):       
            self._inner= dict()        
            self.__getitem__= self._inner.__getitem__
            self.__setitem__= self._inner.__setitem__    
     
    class xD(DD,object):
        def __init__(self): DD.__init__(self)
     
    def test(d):
        d._inner[0]= 1 
        d[0]= 1
        print "d[0]"
        d[0]
        print "d.__getitem__(0)"
        d.__getitem__(0)
     
    if __name__ == '__main__':
    #    d=D()
    #    print "D---"*20
    #    test(d)
    #    d=DD()
    #    print "DD--"*20
    #    test(d)
        d=xD()
        print "xD--"*20
        test(d)

  20. #20
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    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 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Citation Envoyé par VV33D Voir le message
    Pourquoi Python a-t'il besoin de faire type(x).__getitem__(x, i) , plutôt que getattr(x,'__getitem__')(i) ???
    Il faut lire la doc plus loin.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

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