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 d'opérateur de classe et mise à jour automatique du résultat de l'opération [Python 3.X]


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    ingénieur essai
    Inscrit en
    Juin 2017
    Messages
    35
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : ingénieur essai
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2017
    Messages : 35
    Par défaut surcharge d'opérateur de classe et mise à jour automatique du résultat de l'opération
    Bonjour à tous,

    Je voulais savoir s'il était possible quand on surcharge un opérateur mathématique d'une classe (par exemple +) que le résultat se mette à jour automatiquement?

    imaginons que j'ai la classe Nombre (ce n'est pas mon vrai exemple, mais je simplifie pour se concentrer sur l'essentiel)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    class Nombre():
        def __init__(self,valeur):
            self.valeur = valeur
     
        def mettre_a_jour(self, new_value):
            self.valeur = new_value
     
        def __str__(self):
            return "{}".format(self.valeur)
     
        def __add__(self, other):
            valeur = self.valeur + other.valeur
            return Nombre(valeur)
    donc quand je l'utilise:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    a = Nombre(1)
    b = Nombre(2)
    c = a + b
    print(c)   ### affiche 3 ###
    a.mettre_a_jour(5)
    print(a)    ###affiche 5###
    print(c)    ###affiche 3###
    je voudrais que c soit mis à jour automatiquement quand a est mis à jour.

    actuellement j'utilise plutôt un code comme suit, mais que je voudrais simplifier si c'est possible:
    la classe Observable à deux méthodes [ ajouter_observateur, notifier_observateurs]
    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 Nombre(Observable):
     
        def __init__(self,valeur=0):
            self.valeur = valeur
     
        def mettre_a_jour(self, nouvelle_valeur):
           self.valeur = nouvelle_valeur
           self.notifier_observateurs()     ### je notifie les observateurs 
     
        def __str__(self):
            return "{}".format(self.valeur)
     
    class ResultatAddition(Nombre):
     
        def __init__(self, nombre1, nombre2):
            self.nombre1 = nombre1
            nombre1.ajouter_observateur(self)   ### j'ajoute mon objet à la liste des observateurs du nombre 1
            self.nombre2 = nombre2
            nombre2.ajouter_observateur(self)   ### j'ajoute mon objet à la liste des observateurs du nombre 2
            super().__init__(self)
            self.ajout()
     
     
        def additionner(self):
              self.valeur = nombre1.valeur + nombre2.valeur
     
        ### méthode obligatoire de l'objet observateur qui est appelée par notifier_observateurs
        def update(self):
             self.additionner()
    donc quand je l'utilise, ça donne ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    a = Nombre(1)
    b = Nombre(2)
    c = ResultatAddition(a, b)
     
    print(c)  ### affiche 3 ###
     
    a.mettre_a_jour(5)
     
    print(c)  ### affiche 7 ###
    Guillaume.

  2. #2
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Bonjour

    Si le code appelant écrit:
    alors on créé bien un objet c, à partir de 2 autres.
    Maintenant si vous voulez mettre à jour l'objet lui même, alors la syntaxe, serait plutôt celle-ci :

    chose que vous pouvez surcharger via la méthode __iadd__ :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    def __iadd__(self, other):
            self.valeur = self.valeur + other.valeur
    ou bien si vous maintenez la méthode mettre_a_jour, par souci de cohérence on écrira plutôt :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    def __iadd__(self, other):
            self.mettre_a_jour(self.valeur + other.valeur)
    Maintenant j'ai l'impression que ce n'est pas trop cela que vous voulez faire, mais plutot garder du lien entre plusieurs variables. Dans ce cas, et bien pas le choix, il faut faire une structure (un objet par exemple) qui lui va faire le lien et être le garant de tout ca.

    Par exemple (code écrit acappella, je ne l'ai pas testé) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Somme():
      def __init__(self,a,b):
        self.a = a
        self.b = b
     
      @property
      def c(self): return self.a+self.b
     
    X=Somme(1,2)
    print(X.c)
    X.a=7
    print(X.c)
    Ici, je ne stocke pas c, ça évite de devoir gérer ces mises à jour. Je passe via une property, qui fournit un attribut dynamique à la classe, c'est à dire que c'est un attribut, mais qui n'est pas stocké en mémoire : à chaque fois qu'on le demande il est calculé en fonction de l'état courant de l'objet.

  3. #3
    Membre averti
    Homme Profil pro
    ingénieur essai
    Inscrit en
    Juin 2017
    Messages
    35
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : ingénieur essai
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2017
    Messages : 35
    Par défaut
    bonjour lg_53,

    merci d'avoir pris du temps pour répondre.
    je suis d'accord que c = a+b crée un nouvel objet qu'il faut que je sauvegarde, mais quand je mets à jour a ou b, il faut que c soit mis à jour, pas qu'un nouvel objet soit créé.


    Dans ton deuxième exemple, il faudrait que a et b soit des objets de la classe Somme ou d'une classe parente de Somme. Mais ça, ma classe Nombre et ResultatAddition le font déjà:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Somme():
      def __init__(self,a,b):
        self.a = a
        self.b = b
     
      @property
      def c(self): return self.a+self.b
     
    X=Somme(1,2)
    print(X.c)
    X.a=7
    print(X.c)
    le but d'utiliser les surcharges d'opérateur serait de pouvoir faire des opérations entre les objets de ma classe, mais aussi de pouvoir chainer ces opérations.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class Nombre():
        pass
     
    a = Nombre(5)
    b = Nombre(6)
    c = Nombre(2)
     
    d = a*b + c
    print(d)
    a.update(10)
    Je me disais que je pourrais peut-être utiliser une liste dans ma classe pour sauver tous les objets que je créée mais j'ai peur d'alourdir encore plus le code, alors que je souhaiterai le simplifier.

    Guillaume.

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 830
    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 830
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par Guillaume.Chevallier Voir le message
    mais quand je mets à jour a ou b, il faut que c soit mis à jour, pas qu'un nouvel objet soit créé.
    Cela n'est pas un comportement naturel d'un langage de prog. Dans les langages en général, une variable est positionnée à une valeur et ensuite n'en change plus tant que ce n'est pas explicitement demandé.
    Si j'écris a=5, b=7 et c=a+b je m'attends à ce que c vaille 12 jusqu'à la fin de mon programme, même si je change ensuite les valeurs de "a" ou "b".

    Python a un comportement qui ressemble assez à ce que tu veux faire quand on copie des objets complexes. Car dans ce cas, la copie reste superficielle. Exemple tab=[1, 2, 3].
    Si j'écris ensuite copie=tab et si je modifie ensuite tab (exemple tab.append("toto")) alors "copie" contient aussi toto. Mais généralement c'est un comportement plus gênant qu'autre chose et qu'on préfère éviter en demandant spécifiquement qu'il ne se fasse pas, via une copie complète => copie=list(tab).
    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]

  5. #5
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    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 738
    Par défaut
    Salut,

    Le pattern observateur est fait pour répondre à ce genre de cas de figure.... et il n'existe pas en natif avec Python, il faut éventuellement profiter de bibliothèques externes ou installer des bibliothèques spécifiques.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  6. #6
    Membre averti
    Homme Profil pro
    ingénieur essai
    Inscrit en
    Juin 2017
    Messages
    35
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : ingénieur essai
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2017
    Messages : 35
    Par défaut
    bonjour Wiztricks,

    le pattern observer que j'utilise est codé simplement, j'avais suivi un tutoriel dessus et qui le résultat m'allait pour l'instant:
    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
     
    from collections import defaultdict
     
     
    class Observable:
     
        def __init__(self):
            self.observers = defaultdict(list) #pour un evenement en clef, j'ai une liste d'observers
     
        def notify_observers(self, event):
            for obs in self.observers[event]:
                obs.update(self)
     
        def add_observer(self, obs, event):
            if not hasattr(obs, 'update'):
                raise ValueError("First argument must be object with notify method")
            self.observers[event].append(obs)
     
        def remove_observer(self, obs, event):
            if obs in self.observers[event]:
                self.observers[event].remove(obs)
                if not self.observers[event]:
                    del self.observers[event]
    Mon problème c'est que je ne vois pas comment faire cohabiter mon pattern Observer avec la surcharge d'opérateur (et si c'est possible). Mais comme je me pose la question, je me dis que d'autres ont dû se la poser et trouver une solution... ou pas.

    est-ce que __add__(self, other) devrait non pas faire le calcul, mais plutôt créer la liaison entre mon_résultat, self et other et ajouter mon_résultat comme observateur de self et other.

  7. #7
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    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 738
    Par défaut
    Citation Envoyé par Guillaume.Chevallier Voir le message
    Mon problème c'est que je ne vois pas comment faire cohabiter mon pattern Observer avec la surcharge d'opérateur (et si c'est possible). Mais comme je me pose la question, je me dis que d'autres ont dû se la poser et trouver une solution... ou pas.
    La surcharge est une méthode comme les autres. Si la valeur change, il va aussi falloir notifier les observateurs.

    Citation Envoyé par Guillaume.Chevallier Voir le message
    est-ce que __add__(self, other) devrait non pas faire le calcul, mais plutôt créer la liaison entre mon_résultat, self et other et ajouter mon_résultat comme observateur de self et other.
    C'est pas compliqué à faire, non?

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  8. #8
    Membre averti
    Homme Profil pro
    ingénieur essai
    Inscrit en
    Juin 2017
    Messages
    35
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : ingénieur essai
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2017
    Messages : 35
    Par défaut
    Pardon j'écris ce message de mon téléphone, donc je n'ai pas les citations, ni la mise en forme

    Sve@r,
    Oui je sais que c'est le fonctionnement normal de la plupart des langages et on est obligé d'utiliser des artifices comme par exemple le patron observateur pour ajouter du dynamisme aux objets.
    Si en math j'écris une fonction y=f(x), je m'attends à ce que y soit mis à jour si x change.

    Wiztricks,
    C'est un peu ce qui me fait peur, créer une usine à schmilblick pour un truc qui s'énonce facilement en français.
    C'était un peu aussi pour ça que je suis venu poser ma question sur le forum, pour essayer d'y voir plus clair et peut-être avoir des réponses.

    Bonne nuit et merci.

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

Discussions similaires

  1. Réponses: 0
    Dernier message: 16/06/2020, 18h02
  2. [AC-2007] Dessin vba sous access avec la classe GDI+mise à jours 2019.
    Par thermo dans le forum VBA Access
    Réponses: 6
    Dernier message: 10/05/2020, 11h39
  3. surcharge d'opérateur avec classes différentes
    Par weird73 dans le forum C++
    Réponses: 7
    Dernier message: 23/01/2013, 18h03
  4. système de mise à jour automatique
    Par eponette dans le forum Web & réseau
    Réponses: 2
    Dernier message: 24/08/2005, 20h17
  5. Mise à jour automatique d'un JTextAera
    Par Vlakyron dans le forum Agents de placement/Fenêtres
    Réponses: 2
    Dernier message: 25/09/2004, 20h11

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