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

  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
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 681
    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 681
    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

  5. #5
    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.

  6. #6
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 801
    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 801
    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]

  7. #7
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 681
    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 681
    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.

  9. #9
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 801
    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 801
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Guillaume.Chevallier Voir le message
    Si en math j'écris une fonction y=f(x), je m'attends à ce que y soit mis à jour si x change.
    Attention aux analogies, car cela ne reste que des analogies. Elles permettent d'illustrer des comportements similaires mais seulement jusqu'à un certain point. L'écriture mathématique n'a pas la même signification que l'écriture informatique. Et puis bon ben Python lui ne fonctionne pas comme ça donc on fait comme il dit qu'il faut faire.

    Mais imaginons un langage tel que tu le décris. Donc j'initialise "a" avec une constante (7), "b" avec une constante (5) puis "c" comme le résultat de "a+b" (12). Ensuite "a" change. Il va falloir repérer toutes les variables qui en dépendent (ici "c" mais peut-être pas que...). Et toutes celles qui dépendent de "c". Et toutes celles qui dépendent de celles qui dépendent de "c". Là déjà... Ah sauf que le changement dans "a" ce n'est plus une constante mais un autre variable (exemple "f"). Ok, "a" dépend maintenant de "f" (l'arbre des possibles qui était déjà une forêt vient de se prendre une claque puissance 10). Et puis ensuite j'écris "f=c" et là mon arbre explose en plein vol.
    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]

  10. #10
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 681
    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 681
    Par défaut
    Citation Envoyé par Guillaume.Chevallier Voir le message
    Si en math j'écris une fonction y=f(x), je m'attends à ce que y soit mis à jour si x change.
    Oui enfin, l'humain va choisir une valeur pour x, calculer f(x) et sortir y =... Et si on assigne à x un nouvelle valeur, l'humain sait qu'il devra refaire le calcul (l'ordinateur... non).

    Citation Envoyé par Guillaume.Chevallier Voir le message
    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
    Vous avez les réponses: traduire la dépendance entre c et (a, b) pour qu'on sache quoi mettre à jour lorsqu'on modifie les variables dont c dépend. Reste à savoir le problème que vous chercher à résoudre ce faisant.

    On peut faire marcher çà plus ou moins facilement, mais au bout du bout ça va servir à quoi, pourquoi êtes vous intéressé de faire marcher çà?

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

  11. #11
    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
    Bien que je ne comprenne toujours pas la nécessité de faire qqch de tordu comme ça, voici un code qui peut répondre au besoin. Il est assez simple et ne fait pas appel au pattern Observer. Il supporte aussi l'assignation, mais là pareil, ca ne fait pas une copie, les 2 nombres sont liés.

    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
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    import operator
     
    class Nombre():
        def __init__(self,valeur):
            self.valeur = valeur
     
        def __str__(self):
            return str(self.valeur)
     
        def __repr__(self):
            return "Nombre(%s)"%self.valeur
     
        def __add__(self, other):
            return Nombredynamique(Operation(self,other,operator.add))
     
        def __mul__(self, other):
            return Nombredynamique(Operation(self,other,operator.mul))
     
        def mettre_a_jour(self, nouvelle_valeur):
           self.valeur = nouvelle_valeur
     
    class Operation():
        def __init__(self, nb1, nb2, op):
            self.nb1 = nb1
            self.nb2 = nb2
            self.op = op
     
        def __str__(self):
            return "(%s,%s,%s)"%(repr(self.nb1),str(self.op),repr(self.nb2))
     
        def result(self):
            return self.op(self.nb1.valeur,self.nb2.valeur)
     
     
    class Nombredynamique(Nombre):
        def __init__(self,operation):
            self.operation=operation
     
        def __repr__(self):
            return str(self.operation)
     
        @property
        def valeur(self):
            return self.operation.result() 
     
        def mettre_a_jour(self, nouvelle_valeur):
           raise RuntimeError("Un nombre dynamique ne peut etre mis à jour")
     
    a=Nombre(2)
    b=Nombre(3)
    c=a+b
    print(c)
    a.mettre_a_jour(5)
    print(c)
    d=Nombre(2)*c
    print(d)
    a.mettre_a_jour(7)
    print(d)
    e=a*b+d
    print(e,'=',repr(e))
    b.mettre_a_jour(4)
    print(e)
    e=a
    print(a,e)
    a.mettre_a_jour(5)
    print(a,e)
    f=a*c
    print(a,b,c,f)
    a=c
    print(a,b,c,f)
    print(repr(c))
    print(repr(f))

  12. #12
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 801
    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 801
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par lg_53 Voir le message
    Bien que je ne comprenne toujours pas la nécessité de faire qqch de tordu comme ça, voici un code qui peut répondre au besoin.
    Je l'ai testé (enfin me suis arrêté à a.mettre_a_jour(5)) mais c'est un bel exercice de style
    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]

  13. #13
    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
    Citation Envoyé par lg_53 Voir le message
    Bien que je ne comprenne toujours pas la nécessité de faire qqch de tordu comme ça, voici un code qui peut répondre au besoin. Il est assez simple et ne fait pas appel au pattern Observer. Il supporte aussi l'assignation, mais là pareil, ca ne fait pas une copie, les 2 nombres sont liés.
    Bonjour Lg_53, bonjour à tous,

    Je viens de voir vos messages. ma question ne fait pas l'unanimité, mais elle vous titille. sinon tu n'aurais pas passer du temps à trouver une solution que je trouve efficace et compréhensible. (et pour cela merci!!! )

    Je vais essayer de répondre à ta question: quelle est "la nécessité de faire qqch de tordu comme ça"?

    Je tiens à préciser que je ne suis pas programmeur, que je me suis mis à Python par nécessité et que je me suis formé seul avec des tutos sur internet. Donc ce que j'ai fais pour l'instant est sûrement très discutable et aurait sûrement été codé différemment par quelqu'un d'autre.

    Mon ordi (raspberry pi) est connecté sur un bus CAN. j'utilise la bibliothèque Python "Pycan" pour récupérer les trames et "Cantools" pour décoder les messages et récupérer les signaux (mes variables d'entrée).
    Donc à chaque fois que j'ai une nouvelle trame, certaines variables sont mises à jour.

    On va dire que je suis dans un premier temps intéressé par les signaux: A, B, C D E et F.

    et que je souhaite calculer:
    R1 = (A+B^2)/C +5*F
    R2 = C*E- 2*A*F

    Et bien sur que les résultats R1 et R2 soient mis à jour à chaque fois qu'une variable change.

    et demain, je souhaiterai calculer R3 =R2/(R1*G)

    une solution a été de créer une classe VariableAbstraite(Observable) ayant deux classes enfants VariableMesuree et VariableCalculee

    VariableAbstraite contient mon couple (valeur, horodatage)
    sa méthode "mettre_a_jour" notifie aussi sa liste d'observateurs

    VariableMesuree est un observateur de mon bus Can
    sa méthode "update" utilise la méthode "mettre_a_jour" de VariableAbstraite

    VariableCalculee est observateur de une ou deux Variables (mesuree ou calculee)

    Ici deux possibilités:
    Soit j'ajoute un paramètre 'Operation' à VariabelCalculee et je mets un switch case (mince ça n'existe pas en python3.8) pour chaque opération (ou une méthode par opération).
    Soit je dérive VariableCalculee pour chaque opération VariableAdd(VariableCalculee), VariableMult(VariableCalculee)

    ce qui au final s'utilise comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    intensite = VariableMesuree(signal1)
    tension = VariableMesuree(signal3)
    longueur = VariableMesuree(signal29)
    largeur = VariableMesuree(signal22)
    hauteur = VariableMesuree(signal8)
     
    puissance = VariableCalculee(intensite,tension, 'MULT')
    ou
    puissance = VariableMult(intensite,tension)
     
    volume = VariableCalculee(hauteur, VariableCalculee(longueur, largeur, 'MULT'), 'MULT')
    c'est faisable, ça marche mais c'est moche et pas très lisible.

    alors que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    puissance = intensite * tension
    volume = hauteur * longueur * largeur
    c'est quand même plus simple et lisible.

    J'espère que ça vous a éclairé sur la chose tordue et pas l'inverse.

    Guillaume.

  14. #14
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 801
    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 801
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Guillaume.Chevallier Voir le message
    Donc à chaque fois que j'ai une nouvelle trame, certaines variables sont mises à jour.

    On va dire que je suis dans un premier temps intéressé par les signaux: A, B, C D E et F.

    et que je souhaite calculer:
    R1 = (A+B^2)/C +5*F
    R2 = C*E- 2*A*F

    Et bien sur que les résultats R1 et R2 soient mis à jour à chaque fois qu'une variable change.
    Une programmation plus classique serait de dire "la variable change quand une nouvelle trame arrive donc c'est quand une nouvelle trame arrive que je change les variables et que j'appelle la fonction qui calcule R1 et celle qui calcule R2"...
    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]

  15. #15
    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
    Citation Envoyé par Sve@r Voir le message
    Une programmation plus classique serait de dire "la variable change quand une nouvelle trame arrive donc c'est quand une nouvelle trame arrive que je change les variables et que j'appelle la fonction qui calcule R1 et celle qui calcule R2"...
    py-can est basé sur des Listeners qui s'enregistrent pour recevoir les notifications quand un nouveau message arrive. J'ai voulu continuer avec le même principe que je trouve intéressant.

    Je dois t'avouer que j'ai dû mal à voir comment faire avec une programmation plus classique dans ce cas là. Sachant que la configuration des variables et des calculs doit être configurable.


    Guillaume.

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

    Citation Envoyé par Guillaume.Chevallier Voir le message
    Je dois t'avouer que j'ai dû mal à voir comment faire avec une programmation plus classique dans ce cas là. Sachant que la configuration des variables et des calculs doit être configurable.
    "configurable" est un sujet d'interface utilisateur. Si l'utilisateur "programme", il peut ajouter/modifier des fonctions et l'interface est toute faite.
    Après si je veux évaluer des expressions arithmétiques de façon répétitives, je peux pousser tous ces calculs dans une chaine de caractères (qui pourrait être un script Python spécifique puisqu'il est fabriqué avec...):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    >>> calculs ='''
    ... R1 = (A+B**2)/C +5*F
    ... R2 = C*E- 2*A*F
    ... '''
    >>>
    Je peux à partir de là avoir un dictionnaire avec la valeur des variables:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    >>> d = dict(A=1, B=2, C=3,E=4, F=10)
    Et j'exécute les calculs:
    pour récupérer les résultats dans le dictionnaire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    >>> d['R1']
    51.666666666666664
    >>> d['R2']
    -8
    >>>
    Ce que je préférerai faire avec une fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    >>> def f(A, B, C, E, F):
    ...     R1 = (A+B**2)/C +5*F
    ...     R2 = C*E- 2*A*F
    ...     return R1, R2
    ...
    >>> f(1, 2, 3, 4, 10)
    (51.666666666666664, -8)
    >>>
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  17. #17
    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,

    oui le but sera d'avoir une interface utilisateur qui permettra de créer le fichier de config (j'avais pensé json ou xml) qui sera téléchargé sur la raspberry en fonction des besoins. Mais bon pour l'instant, je n'ai pas encore réfléchi à cette partie là. Peut-être à tort, car c'est peut-être la structure de mon fichier de config qui pourrais dicter une partie de ce que je suis en train de faire.
    Mais pour l'utilisateur final, python devra être invisible.

    Je ne connaissais pas la fonction "exec" et le fait de pouvoir exécuter une chaine de caractères. c'est une option intéressante pour lire un fichier de config.


    En tout cas, merci à tous pour votre participation à ce sujet. J'ai eu une réponse à ma question et d'autres voies à explorer pour faire différemment.

    Guillaume.

  18. #18
    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
    Ton besoin ressemble donc plus à de la métaprogrammation. Tu cherches à mettre en place, qqch qui, en fonction de paramètre, écrira un code qui pourra s'éxécuter sur ton Raspberry.

    Un peu comme cmake par exemple, qui permet de générer un Makefile, Makefile qui une fois éxécuté permet de compiler un code C++.
    Un peu comme php, qui lui va dynamiquement écrire un code html.

    Et donc finalement ton input, que tu appel fichier de configuration, ca peut être lui même un code. Un code d'un langage connu, ou d'une syntaxe que toi tu auras défini. Ou bien une structure plus orienté data, comme un json ou autre format, que vous pouvez aussi créér vous même.

    Dans votre fichier d'input, vous souhaitez juste faire de l'arithmétique, ou bien aussi des choses plus compliqué comme des conditions, des boucles ou des choses comme ca ?

    La solution que je vous ai proposé devrait pouvoir répondre à votre besoin. exec aussi, mais là attention, grosse mise en garde, ca constitue une faille de sécurité très importante. Car dans votre chaine de caractère, vous pouvez mettre n'importe quel instruction de code python, et exec va l’exécuter.

  19. #19
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 681
    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 681
    Par défaut
    Citation Envoyé par Guillaume.Chevallier Voir le message
    pour l'instant, je n'ai pas encore réfléchi à cette partie là. Peut-être à tort, car c'est peut-être la structure de mon fichier de config qui pourrais dicter une partie de ce que je suis en train de faire.
    Mais pour l'utilisateur final, python devra être invisible.
    Il y a un gap entre ce qui pourra être fourni par l'utilisateur et ce que va pouvoir en faire le programme derrière. Ne serait ce que s'assurer que ça a du sens (à la fois côté syntaxe et sens) puis qu'on pourra en faire quelque chose.

    Et côté Python, çà se résumera toujours à exécuter une ou des fonctions qui restent à fabriquer (soit par le programmeur et son éditeur, soit automatiquement à partir du fichier de configuration).

    De fait les 2 n'ont aucun rapport... et vouloir les "mélanger" ajoute de une complexité (quand on programme on découpe le problème en morceaux réalisables et on évite d'amalgamer).

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

  20. #20
    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
    Citation Envoyé par wiztricks Voir le message
    Il y a un gap entre ce qui pourra être fourni par l'utilisateur et ce que va pouvoir en faire le programme derrière. Ne serait ce que s'assurer que ça a du sens (à la fois côté syntaxe et sens) puis qu'on pourra en faire quelque chose.

    Et côté Python, çà se résumera toujours à exécuter une ou des fonctions qui restent à fabriquer (soit par le programmeur et son éditeur, soit automatiquement à partir du fichier de configuration).

    De fait les 2 n'ont aucun rapport... et vouloir les "mélanger" ajoute de une complexité (quand on programme on découpe le problème en morceaux réalisables et on évite d'amalgamer).

    - W
    Bonjour Wiztrick,

    Il va de soit que le fichier de configuration doit être "normé" pour éviter d'envoyer n'importe quoi vers le programme. Et le fichier de config devra être édité et vérifié par un outil à créer.
    Côté python, le programme crée des objets et des interactions entre objets en fonction de la configuration donnée pour renvoyer les résultats voulus.

    Par contre, je ne suis pas d'accord que les deux n'ont aucun rapport car justement le programme doit interpréter la configuration. Donc, en fonction de la structure du fichier de configuration, je dois créer l'interpréteur adéquat. Ou l'inverse


    Guillaume.

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

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