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 :

Surcharge de l'opérateur =


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2005
    Messages
    130
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 130
    Par défaut Surcharge de l'opérateur =
    Bonjour à tous,

    Est-il possible de surcharger l'opérateur = en python ?
    J'arrive à tout redéfinir, à peu près, suite à la lecture de http://www.python.org/doc/2.4.1/lib/operator-map.html
    Mais rien sur l'opérateur =, et malheureusement c'est celui là dont j'ai besoin.

    Avez-vous une idée?

    Merci d'avance

  2. #2
    Membre émérite

    Profil pro
    Inscrit en
    Août 2004
    Messages
    723
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 723
    Par défaut
    Il ne t'est pas possible de faire autrement ?
    Ça m'étonnerait qu'on puisse le surcharger.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2005
    Messages
    130
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 130
    Par défaut
    arf... je n'ai pas vraiment le choix...
    A vrai dire, je dois pouvoir utiliser une classe comme si c'était un type prédéfini, comme un float ou un int par exemple.

    Par exemple:
    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
     
    class BaseTypeWrapper (object):
        def __init__ (self):
            self.value = None
     
        def __eq__(self, val):
            return self.value == val
     
        def __add__(self, val):
            return self.value + val
     
        def __sub__(self, val):
            return self.value - val
     
        def __mul__(self, val):
            return self.value * val
     
        def __div__(self, val):
            return self.value / val
    Il ne me manque que l'opérateur =, pour éviter qu'à chaque affectation, Python me transformer le type de mon instance dans le type affecté:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    test =  BaseTypeWrapper()
    test=5
    => test est du type int, alors que je veux qu'il soit du type BaseTypeWrapper, avec self.value == 5


    Il n'existe pas un workaround pour faire ce genre de chose ?



    EDIT: __set__ a l'air de ressembler à ce que je cherche, mais je n'étais pas tombé dessus, je n'ai vu que les autres... Je vais essayer de comprendre comment ça s'utilise, ca ne me parle pas plus que ça, de visu.

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2005
    Messages
    130
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 130
    Par défaut
    Bon c'est malheureux, mais je ne comprends pas du tout comment peut fonctionner __set__ et __get__
    J'ai pourtant fait correctement fonctionner l'exemple ici: http://users.rcn.com/python/download/Descriptor.htm
    Par contre, lorsque je tente de faire de même avec mon objet, l'opérateur égal n'est pas surchargé:

    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 Observable (object):
        def __init__ (self):
            self.value = None
            self.subscribers = []
     
        def __set__ (self, obj, val):
            self.value = val
            for subscriber in self.subscribers:
                subscriber.set(val)
     
        def __get__(self, obj, val):
            return self.value
     
        def __eq__(self, val):
            return self.value == val
     
        def __add__(self, val):
            return self.value + val
     
        def __sub__(self, val):
            return self.value - val
     
        def __mul__(self, val):
            return self.value * val
     
        def __div__(self, val):
            return self.value / val
     
     
        def subscribe (self, subscriber):
            self.subscribers.append(subscriber)
    Cas prouvant que l'opérateur n'est pas surchargé:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    bob = Observable()
    bob = 5
    print type(bob)
    Sortie:

  5. #5
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    105
    Détails du profil
    Informations personnelles :
    Âge : 57
    Localisation : Suisse

    Informations forums :
    Inscription : Septembre 2007
    Messages : 105
    Par défaut
    Bonjour,

    Je crois que c'est normal, car tu veux modifier un attribut et dans ce cas il faut utiliser __setattr__.

    Voici un exemple d'implémentation d'un pseudo type constant:
    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
    #!/usr/bin/python
    # -*- coding:Utf-8 -*-
     
    class Const:
     
        def __init__ (self):
            Const.__items = {}
     
        def __getattr__ (self, attr):
            try:
                return Const.__items [attr]
            except:
                return self.__dict__ [attr]
     
        def __setattr__ (self, attr, value):
            if attr in Const.__items.keys ():
                raise "Impossible de réassigner la valeur (%s) Ã* la constante: %s" % (value, attr)
            else:
                Const.__items [attr] = value
     
        def __str__ (self):
            return "\n".join (["%s: %s" % (str (k), str (v)) for k,v in Const.__items.items ()])
     
    if __name__ == "__main__":
        import sys
     
        MyConst = Const ()
        MyConst.spam = 2
        MyConst.eggs = 3
        try:
            MyConst.spam = 1
        except:
            print sys.exc_info()[0]
        print "MyConst.spam = %s\nMyConst.eggs = %s" % (MyConst.spam, MyConst.eggs)
    Salutations.

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2005
    Messages
    130
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 130
    Par défaut
    En fait, ce que je veux, c'est utiliser mon type Observable comme si c'était un type prédéfini (je cache le fait que ce soit une classe qui enrobe une valeur).
    Je veux donc vraiment y accéder de la même manière qu'un int, à savoir comme je le fais plus haut dans mon test qui marche pas.

    Si j'utilise __getattr__ et __setattr__, je vais être obligé d'appeler explicitement bob.value = 5 (dans mon exemple), et non pas seulement bob=5.

  7. #7
    Membre émérite
    Homme Profil pro
    Inscrit en
    Décembre 2007
    Messages
    758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 758
    Par défaut
    bonjour,

    c'est normal. il y a une différence entre l'exemple que tu as trouvé et ton propre cas.

    dans l'exemple, il s'agit de redéfinir l'opérateur "=" pour des attributs d'un objets.
    dans ton cas, il n'y a pas d'attribut d'objet mais simplement un objet.

    en gros, tu peux redéfinir l'opérateur "=" si tu es dans un cas comme ceci:

    toto.value = 5

    mais pas si tu veux faire ça:

    toto = 5

    Dans le premier cas, l'opérateur "=" dépend de la nature de l'objet toto, dans le second, l'opérateur "=" échappe à ce type de contrôle.

    C'est vrai que c'est quelque chose que l'on fait dans d'autres langages comme le c++ mais il y a une différence fondamentale avec python. L'opérateur "=" n'a pas du tout la même signification ceci est lié notamment au fait que python est un langage à typage dynamique.

    en c++, d'abord on déclare le type de l'objet. du coup, lorsqu'on utilise l'opérateur =, c'est l'opérateur = de l'objet crée qui est invoqué.

    en python, quand on utilise l'opérateur =, il est résolu dans un contexte d'un niveau supérieur à l'objet:

    toto = 5

    python fait ceci:

    - il alloue un espace mémoire pour contenir un entier
    - il crée un lien entre le nom "toto" et l'adresse mémoire (le pointeur) de l'entier

    du coup, le nom "toto" peut être utilisé pour référencer d'autres pointeurs que le pointeur qu'il référençait initialement (ce qui peut entrainer le ramasse miettes sur une adresse mémoire qui n'est plus référencée).

    pour résumer, en c++ quand on utilise l'opérateur = on sait déjà quel type d'objet on manipule. en python, on ne connait le type de l'objet qu'après l'appel de l'opérateur "=".

    pour pouvoir faire ce que tu souhaites, il faudrait passer par un autre opérateur que "=" ou alors utiliser une méthode "set".

    à moins de changer le contexte et de travailler sur des attributs de classe.

    j'espère que j'ai pas été trop brouillon dans mon explication.

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2005
    Messages
    130
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 130
    Par défaut
    Ok très bonne explication, c'est très clair pour moi... Par contre, je suis extrêmement embêté car cette impossibilité de Python va me forcer à aller modifier environ 400 affectations dans mon projet...

    Tu connaîtrais pas un contournement, par hasard, qui permettrait de simuler la surcharge de l'opérateur = pour un objet ?


  9. #9
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    105
    Détails du profil
    Informations personnelles :
    Âge : 57
    Localisation : Suisse

    Informations forums :
    Inscription : Septembre 2007
    Messages : 105
    Par défaut
    Bonjour,

    Si j'ai bien compris ta question, tu désires définir l'opération d'affectation pour un objet.

    Si c'est le cas, pour les attributs il faut utiliser la méthode __setattr__. Sinon, je te propose de regarder du côté de la méthode __set__.

    Tu trouveras plus d'information dans la doc de Python.

    Salutations.

Discussions similaires

  1. Surcharge de l'opérateur new
    Par :Bronsky: dans le forum C++
    Réponses: 17
    Dernier message: 27/10/2010, 21h33
  2. Réponses: 8
    Dernier message: 29/08/2006, 00h56
  3. [C#] Surcharge de l'opérateur ==
    Par LE NEINDRE dans le forum Windows Forms
    Réponses: 3
    Dernier message: 18/07/2006, 16h19
  4. Réponses: 6
    Dernier message: 12/07/2006, 15h34
  5. Réponses: 15
    Dernier message: 25/01/2005, 16h51

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