IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Surcharge des opérateurs en Python : redéfinir dans une classe Python les opérateurs d'addition, de multiplication et de puissance pour les nombres complexes,
Un tutoriel de Denis Hulo

Le , par User

0PARTAGES

10  0 
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 :

Surcharge des opérateurs en Python

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



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

Une erreur dans cette actualité ? Signalez-nous-la !

Avatar de fred1599
Expert éminent https://www.developpez.com
Le 12/04/2022 à 11:12
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
2  0 
Avatar de MPython Alaplancha
Membre expérimenté https://www.developpez.com
Le 12/04/2022 à 11:41
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
2  0 
Avatar de wiztricks
Expert éminent sénior https://www.developpez.com
Le 10/04/2022 à 23:23
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
1  0 
Avatar de Sve@r
Expert éminent sénior https://www.developpez.com
Le 11/04/2022 à 13:00
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
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
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
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)...
1  0 
Avatar de MPython Alaplancha
Membre expérimenté https://www.developpez.com
Le 10/04/2022 à 21:53
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)
0  0 
Avatar de papajoker
Expert confirmé https://www.developpez.com
Le 10/04/2022 à 22:30
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
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)
0  0 
Avatar de MPython Alaplancha
Membre expérimenté https://www.developpez.com
Le 11/04/2022 à 11:10
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?
0  0 
Avatar de User
Rédacteur/Modérateur https://www.developpez.com
Le 11/04/2022 à 12:01
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.
0  0 
Avatar de User
Rédacteur/Modérateur https://www.developpez.com
Le 11/04/2022 à 17:39
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
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
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.
0  0 
Avatar de Sve@r
Expert éminent sénior https://www.developpez.com
Le 11/04/2022 à 18:08
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.
0  0