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 des opérateurs en Python [Tutoriel]


Sujet :

Python

  1. #1
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 261
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 261
    Points : 19 424
    Points
    19 424
    Billets dans le blog
    63
    Par défaut Surcharge des opérateurs en Python
    Bonjour,

    Après avoir défini les opérations d'addition et de multiplication pour les nombres complexes, on explique comment redéfinir les opérateurs « + », « * » et « ** » dans une classe Python à l'aide de la surcharge d'opérateurs :


    Représentation algébrique d'un nombre complexe :

    Nom : representation_algebrique.png
Affichages : 301004
Taille : 16,7 Ko

    Enfin, pour compléter cette présentation, on explique comment ajouter à cette classe l'opérateur de comparaison « == » entre deux nombres complexes.

    Bonne lecture à tous
    Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération

    Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
    Gestion sur un planning des présences et des absences des employés
    Gestion des rendez-vous sur un calendrier mensuel


    Importer un fichier JSON dans une base de données Access :
    Import Fichier JSON

  2. #2
    Membre expérimenté
    Avatar de MPython Alaplancha
    Homme Profil pro
    Paysan à 3 francs six sous
    Inscrit en
    Juin 2018
    Messages
    870
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Paysan à 3 francs six sous
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Juin 2018
    Messages : 870
    Points : 1 522
    Points
    1 522
    Billets dans le blog
    4
    Par défaut
    Bonjour,
    En termes de sémantique, ne serait-il pas plus juste de parler de surcharge des méthodes spéciales utilisées par les opérateurs?
    ...
    Merci du partage (j'avais vu le blog)
    #Rien de nouveau sous le soleil, tout est vanité comme courir après le vent!
    Developpement pour Android avec Python3/Kivy/Buildozer

  3. #3
    Expert confirmé Avatar de papajoker
    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2013
    Messages
    2 103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nièvre (Bourgogne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2013
    Messages : 2 103
    Points : 4 449
    Points
    4 449
    Par défaut
    bonjour,
    les nombres complexes sont trop complexes pour moi, donc je ne parlerais que de python.

    Dommage qu'il n'y ai pas de test du type dans __add__ ... __eq__

    Et puisque Complexe(5) est valide, on devrait pouvoir ajouter un entier à un complexe ? ou l'inverse ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        def __radd__(self, other):
            if isinstance(other, int):
                return self.__add__(Complexe(other))
            else:
                raise TypeError("Type non supporté pour un Complexe")
    print(1 + Complexe(2,6))
    print(Complexe(2,6) +1)

    - Peut-être aussi surcharger __bool__() ?
    - Puisque la sortie texte est du type "x + xi" , il pourrait être amusant d'avoir un "2 + 5i" + Complexe(7,2) ?


    Si vous souhaitez avoir une liste plus complète des opérateurs, je vous invite à consulter cette page.
    En fait, dans ce lien/blog la liste est loin d'être complete par rapport à la documentation officielle (comme "+=" par exemple)
    $moi= ( !== ) ? : ;

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Citation Envoyé par Hominidé Voir le message
    En termes de sémantique, ne serait-il pas plus juste de parler de surcharge des méthodes spéciales utilisées par les opérateurs?
    La surcharge des opérateurs, c'est un "sucre" syntaxique permettant de remplacer "3 + 5" par un appel de fonction (ici operator.add(3, 5)).

    La surcharge de méthodes, c'est un polymorphisme ou plusieurs méthodes/fonctions avec le même nom mais acceptant des paramètres et des type de retour différents. Lorsqu'on appelle une de ces fonctions, le compilateur ou l'interpréteur va matcher la "bonne" en fonction du type de ses arguments.

    De fait, cela n'existe pas sur Python, mais on peut faire un équivalent à partir des (*args, **kwds) reçus par une fonction ou de functools.singledispatch.

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

  5. #5
    Membre expérimenté
    Avatar de MPython Alaplancha
    Homme Profil pro
    Paysan à 3 francs six sous
    Inscrit en
    Juin 2018
    Messages
    870
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Paysan à 3 francs six sous
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Juin 2018
    Messages : 870
    Points : 1 522
    Points
    1 522
    Billets dans le blog
    4
    Par défaut
    Bonjour,
    Citation Envoyé par wiztricks
    De fait, cela n'existe pas sur Python, mais on peut faire un équivalent à partir des (*args, **kwds) reçus par une fonction ou de functools.singledispatch.
    Merci du retour. Je ne mettais jamais penché sur functools.singledispatch...

    Citation Envoyé par wiztricks
    La surcharge de méthodes, c'est un polymorphisme ou plusieurs méthodes/fonctions avec le même nom mais acceptant des paramètres et des type de retour différents. Lorsqu'on appelle une de ces fonctions, le compilateur ou l'interpréteur va matcher la "bonne" en fonction du type de ses arguments.
    Du coup lorsque l'on redéfinie une méthode lors d'un héritage de classe, il est impropre de parler de surcharge de méthode?
    #Rien de nouveau sous le soleil, tout est vanité comme courir après le vent!
    Developpement pour Android avec Python3/Kivy/Buildozer

  6. #6
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 261
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 261
    Points : 19 424
    Points
    19 424
    Billets dans le blog
    63
    Par défaut
    Merci à vous 3 pour vos commentaires et précisions

    Je vais voir pour le lien vers la liste plus complète des opérateurs.

    Cordialement.
    Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération

    Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
    Gestion sur un planning des présences et des absences des employés
    Gestion des rendez-vous sur un calendrier mensuel


    Importer un fichier JSON dans une base de données Access :
    Import Fichier JSON

  7. #7
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    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 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Bonjour

    Les methodes __add__ (et autres) partent toutes du principe qu'on additionne (et autres opérations) deux complexes.
    Ce qui est vrai dans l'absolu car en mathématiques, tous les ensembles s'incluent les uns les autres. Les relatifs incluent les entiers en y rajoutant un sens de lecture, les décimaux incluent les relatifs en y rajoutant des parties de 10, les rationnels incluent les décimaux en y rajoutant des fractions autres que 10, les irrationnels incluent les rationnels en y rajoutant des nombres qui ne peuvent pas s'écrire sous forme de fraction, et les complexes incluent les irrationnels en y rajoutant une partie imaginaire.
    Ainsi si a=2+3i et b=5, alors a+b sont bien l'addition de deux complexes au sens strict du terme puisqu'un naturel fait partire de l'ensemble des complexes. Mais ton code, lui, ne le permet pas...

    Code python : 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 cComplex:
    	def __init__(self, reel=0, img=0):
    		(self.reel, self.img)=(reel, img)
    	# __init__()
     
    	def __str__(self):
    		return "%s, %si" % (self.reel, self.img)
    	# __str__()
     
    	def __add__(self, other):
    		if isinstance(other, (int, float)): other=self.__class__(other, 0)
    		elif isinstance(other, self.__class__): pass
    		else: raise TypeError("on ne peut pas additionner un complexe avec un {}".format(type(other).__name__))
     
    		return self.__class__(self.reel + other.reel, self.img + other.img)
    	# ___add__()
     
    	def __radd__(self, n): return self+n
    # cComplex()
     
    a=cComplex(5, 2)
    print(a)
    print(a+1)
    print(1+a+1)
    print(a+cComplex(2, 2))
    print(a+"toto")

    Ensuite malheureusement c'est un peu dommage de faire un tutoriel pour un type déjà naturellement implémenté en Python
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    a=5+2j
    print(a)
    print(a+1)
    print(1+a+1)
    print(a+2+2j)
    print(a+"toto")

    Citation Envoyé par papajoker Voir le message
    Puisque la sortie texte est du type "x + xi" , il pourrait être amusant d'avoir un "2 + 5i" + Complexe(7,2) ?
    C'est possible (en fait la base c'est convertir "2 + 5i" en complexe). Donc une méthode de classe qui décortique la string et retourne un complexe, du style
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    @classmethod
    def fromString(cls, s):
    	(reel, im)=...(extraction de s)...
    	return cls(reel, img)
    # fromString()
    Ensuite "2 + 5i + Complexe(7, 2)" s'écrira Complexe.fromString("2 + 5i") + Complexe(7, 2)...
    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]

  8. #8
    Rédacteur/Modérateur

    Avatar de User
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    8 261
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 8 261
    Points : 19 424
    Points
    19 424
    Billets dans le blog
    63
    Par défaut
    Bonjour,

    Citation Envoyé par Sve@r Voir le message
    ...
    Ce qui est vrai dans l'absolu car en mathématiques, tous les ensembles s'incluent les uns les autres. Les relatifs incluent les entiers en y rajoutant un sens de lecture, les décimaux incluent les relatifs en y rajoutant des parties de 10, les rationnels incluent les décimaux en y rajoutant des fractions autres que 10, les irrationnels incluent les rationnels en y rajoutant des nombres qui ne peuvent pas s'écrire sous forme de fraction, et les complexes incluent les irrationnels en y rajoutant une partie imaginaire.
    Ainsi si a=2+3i et b=5, alors a+b sont bien l'addition de deux complexes au sens strict du terme puisqu'un naturel fait partire de l'ensemble des complexes. Mais ton code, lui, ne le permet pas...
    Un nombre réel étant un nombre complexe dont la partie imaginaire est nulle, je suis resté sur la définition de la somme de 2 nombres complexes qui a pour partie réelle la somme des parties réelles de ces 2 nombres, et pour partie imaginaire la somme de leurs parties imaginaires.

    Je n'ai pas voulu gérer tous les cas de figures pour ne pas perdre le lecteur.

    D'autre part, tu sembles vouloir gérer également les réels au niveau de l'addition, dans ce cas pourquoi ne pas le faire aussi au niveau de l'affichage :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    a=cComplex(1.0,1.0)
    b=cComplex(1.5,-1.0)
    print(a+b)
    Ton code affiche :
    2.5, 0.0i

    Autant afficher simplement 2.5 dans ce cas.

    Ensuite malheureusement c'est un peu dommage de faire un tutoriel pour un type déjà naturellement implémenté en Python
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    a=5+2j
    print(a)
    print(a+1)
    ...
    En effet, beaucoup de choses sont déjà implémentées en Python, mais en fait je n'ai pas voulu créer une librairie de plus (cf. cmath).
    J'ai juste essayé de montrer simplement comment mettre en place ce type de surcharge, et il m'a semblé que les nombres complexes était un bon exemple pour le faire, quand bien même cela existe déjà en mieux

    Cordialement.
    Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération

    Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
    Gestion sur un planning des présences et des absences des employés
    Gestion des rendez-vous sur un calendrier mensuel


    Importer un fichier JSON dans une base de données Access :
    Import Fichier JSON

  9. #9
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    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 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par User Voir le message
    Je n'ai pas voulu gérer tous les cas de figures pour ne pas perdre le lecteur.
    A mon avis c'était le contraire, gérer tous les cas de figure pour justement montrer au lecteur qu'il faut penser à plein de trucs (et s'il est perdu il prend son temps). J'ai écrit une classe "fractions" (en fait je suis parti de cet objet pour faire cet exemple) j'ai géré le cas "-x" mais aussi le cas "+x" (opérateur "__pos__" à réécrire sinon l'expression n'est pas reconnue), le cas "x-y", le cas "-y+x" (qui, même s'il donne la même chose, n'est pas la même opération), etc...

    Citation Envoyé par User Voir le message
    D'autre part, tu sembles vouloir gérer également les réels au niveau de l'addition, dans ce cas pourquoi ne pas le faire aussi au niveau de l'affichage
    L'affichage n'était pas le but de l'exemple. Je l'ai écrit minimaliste juste pour vérifier la validité des calculs.
    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 confirmé Avatar de papajoker
    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2013
    Messages
    2 103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nièvre (Bourgogne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2013
    Messages : 2 103
    Points : 4 449
    Points
    4 449
    Par défaut
    Citation Envoyé par User Voir le message
    il m'a semblé que les nombres complexes était un bon exemple pour le faire
    Mais dans mon cas, malheureusement cela complique la chose : je n'ai qu'un très très vague souvenir d'avoir "vu" les nombres complexes, il y à 40 ans. Donc baser une technique python sur une chose "complexe" pour moi ne va certainement pas aider puisque déjà rebuté dès le postula de départ.

    Un objet plus compréhensible serait pour moi par exemple une classe Color(r,g,b) (datetime c'est déjà fait...). Ici, c'est normalement plus parlant pour tous les développeurs et montre aussi que ce n'est pas uniquement réservé pour des mathématiques pures

    Comme Sve@r, je pense qu'il faut au contraire montrer "trop" de cas pour aider le lecteur a imaginer des possibilités et puisque les nombres compexes existent, on est limité à faire que du exact :
    Moi qui fait du bash, par exemple je pourais faire un load/save de cette façon "objet >> ./monfichier.json" "objet << ./monfichier.json" et ici c'est clairement un détournement (pour save()) et pas conseillé puisque gros rique d'incompréhension par les autres développeurs qui reprennent le projet
    $moi= ( !== ) ? : ;

  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
    Hello,

    Je trouve le tutoriel très bien, et à mon sens, comme tout tutoriel, il est très rare qu'on y envoi tous les possibles...

    À mon sens, cela donne envie de continuer ce qui a été commencé, en y ajoutant des opérateurs et vérifier qu'on a bien compris ce que l'auteur a écrit.
    D'ailleurs c'est très bien de renvoyer vers une page donnant la liste des opérateurs existants.

    Mon petit doute, est juste un détail qui a peu d'importance... le fait que se soit du niveau "confirmé" serait en fait "confirmé" si on considère un débutant Python apprenant le langage, mais "débutant" si on considère un débutant en POO avec un niveau "confirmé" en Python.
    Étant donné que je considère cela comme de l'apprentissage POO et non un apprentissage Python, peut-être que je donnerai un point de précision sur l'objectif.

    Techniquement c'est suffisant et il n'y a pas grand chose à y ajouter à moins d'alourdir inutilement, et de démotiver le lecteur.

    C'est évidemment mon avis perso
    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
    Membre expérimenté
    Avatar de MPython Alaplancha
    Homme Profil pro
    Paysan à 3 francs six sous
    Inscrit en
    Juin 2018
    Messages
    870
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Paysan à 3 francs six sous
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Juin 2018
    Messages : 870
    Points : 1 522
    Points
    1 522
    Billets dans le blog
    4
    Par défaut
    Bonjour,
    Citation Envoyé par papajoker Voir le message
    Mais dans mon cas, malheureusement cela complique la chose : je n'ai qu'un très très vague souvenir d'avoir "vu" les nombres complexes, il y à 40 ans. Donc baser une technique python sur une chose "complexe" pour moi ne va certainement pas aider puisque déjà rebuté dès le postula de départ.

    Un objet plus compréhensible serait pour moi par exemple une classe Color(r,g,b) (datetime c'est déjà fait...). Ici, c'est normalement plus parlant pour tous les développeurs et montre aussi que ce n'est pas uniquement réservé pour des mathématiques pures.
    J'imagine qu'aucun tutoriel ne pourrait faire l'unanimité.
    Moi non plus je ne suis pas trop math. D'ailleurs lors de mon apprentissage en python, il m'est arrivé esquiver des approches trop matheux, car je les trouvais peu ludiques et surtout je n'arrivais pas à voir en quoi cela pouvait me servir... puis vient le moment où j'ai besoin de certaine notion de math/géométrie pour réaliser un truc et là étonnamment ce que je trouvais austère l'est beaucoup moins

    En ce qui concerne les nombres complexes, ce ne sont pas non plus des notions trop avancées pour matheux. Ce tutoriel reste accessible au plus grand nombre
    #Rien de nouveau sous le soleil, tout est vanité comme courir après le vent!
    Developpement pour Android avec Python3/Kivy/Buildozer

Discussions similaires

  1. Réponses: 7
    Dernier message: 02/12/2007, 21h43
  2. Surcharge des opérateurs ?
    Par kedare dans le forum Ruby
    Réponses: 3
    Dernier message: 06/11/2006, 23h47
  3. Variables polyvalentes et surcharge des opérateurs
    Par Antoine_935 dans le forum C++
    Réponses: 14
    Dernier message: 08/09/2006, 12h38

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