Redéfinir un opérateur
Résolu/Fermé
MemeTech
Messages postés
90
Date d'inscription
mercredi 14 août 2019
Statut
Membre
Dernière intervention
7 janvier 2021
-
1 nov. 2019 à 14:46
MemeTech Messages postés 90 Date d'inscription mercredi 14 août 2019 Statut Membre Dernière intervention 7 janvier 2021 - 3 nov. 2019 à 15:33
MemeTech Messages postés 90 Date d'inscription mercredi 14 août 2019 Statut Membre Dernière intervention 7 janvier 2021 - 3 nov. 2019 à 15:33
6 réponses
Bonjour,
Toutes les opérations passent par les méthodes spéciales de python, par ex. quand on fait 1 + 2, cela passe par la méthode int.__add__
https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types
On ne peut heureusement pas redéfinir les méthodes des types de bases python, sinon bonjour les bugs que cela pourrait engendrer.
La seule solution est donc de définir ton propre type.
C'est plus contraignant que de saisir un simple nombre, mais au moins on a le choix.
Toutes les opérations passent par les méthodes spéciales de python, par ex. quand on fait 1 + 2, cela passe par la méthode int.__add__
https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types
On ne peut heureusement pas redéfinir les méthodes des types de bases python, sinon bonjour les bugs que cela pourrait engendrer.
>>> int.__add__ = lambda s, v: s + v Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't set attributes of built-in/extension type 'int'
La seule solution est donc de définir ton propre type.
import math class Int: def __init__(self, v): self.v = v def __mul__(self, v): print('on me demande de multiplier') return round(self.v * v, 3) sqrt = lambda n: round(math.sqrt(n), 3) print(Int(5) * sqrt(2))
C'est plus contraignant que de saisir un simple nombre, mais au moins on a le choix.
yg_be
Messages postés
23406
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 décembre 2024
Ambassadeur
1 557
1 nov. 2019 à 16:46
1 nov. 2019 à 16:46
bonjour, tu as donc une application, un utilisateur, un interpréteur, une série de traitements, des résultats, et un programme.
quel est le lien entre tout cela?
quel composant essaies-tu de créer ou de modifier?
quel est le lien entre tout cela?
quel composant essaies-tu de créer ou de modifier?
MemeTech
Messages postés
90
Date d'inscription
mercredi 14 août 2019
Statut
Membre
Dernière intervention
7 janvier 2021
1
2 nov. 2019 à 11:11
2 nov. 2019 à 11:11
Désolé pour le retard.
En gros, mon appli charge des fonctions mathématiques et des classes dans l'interpréteur Python que l'utilisateur peut utiliser :
>>> prime (97) # L'utilisateur veut savoir si 97 est premier.
True
>>> _ # L'utilisateur est invité à taper une autre commande.
Si celui-ci tape :
>>> sqrt (2) # Pas besoin de davantage expliciter :-D
1.414
On voit ici que la précision à été limitée à trois décimales car j'ai écrit cette fonction, la valeur de retour est donc traitée.
Autre exemple :
>>> 5 * sqrt (2)
7.069999999999999
Hum !...
Vous avez très sûrement cerné le problème ; - )
Je souhaite donc pouvoir traiter aussi les résultats avec les opérations de base
En espérant avoir été plus clair cette fois !
En gros, mon appli charge des fonctions mathématiques et des classes dans l'interpréteur Python que l'utilisateur peut utiliser :
>>> prime (97) # L'utilisateur veut savoir si 97 est premier.
True
>>> _ # L'utilisateur est invité à taper une autre commande.
Si celui-ci tape :
>>> sqrt (2) # Pas besoin de davantage expliciter :-D
1.414
On voit ici que la précision à été limitée à trois décimales car j'ai écrit cette fonction, la valeur de retour est donc traitée.
Autre exemple :
>>> 5 * sqrt (2)
7.069999999999999
Hum !...
Vous avez très sûrement cerné le problème ; - )
Je souhaite donc pouvoir traiter aussi les résultats avec les opérations de base
En espérant avoir été plus clair cette fois !
yg_be
Messages postés
23406
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 décembre 2024
1 557
2 nov. 2019 à 11:42
2 nov. 2019 à 11:42
peux-tu partager le code de ton appli, et donner un exemple de formule que tu veux également pouvoir traiter?
MemeTech
Messages postés
90
Date d'inscription
mercredi 14 août 2019
Statut
Membre
Dernière intervention
7 janvier 2021
1
Modifié le 2 nov. 2019 à 14:12
Modifié le 2 nov. 2019 à 14:12
Ce code est découpé en deux grandes parties : une pour les fonctions de base (sqrt, prime ou encore les fonctions trigonométriques), une pour tous les modules que l'utilisateur a le choix de charger au démarrage (Des classes pour manipuler des objets comme des vecteurs, des boules ou des rectangles).
Il y en a une dernière pour charger un certain nombre de constantes mathématiques comme pi, e ou encore la masse du Soleil, d'un proton...
Pour obtenir un retour formaté (pour éviter les résultats du genre -0.000000000000001 ou (3j - 0), quoi), j'ai fait une fonction qui traite le nombre et le renvoie bien propre et arrondi au nombre de décimales qu'on lui a demandé.
C'est la fonction trans (x) qu'on retrouve souvent.
Je ne vais pas mettre son code ici, ce serait inutile, en plus, il est moche : - )
Voilà un aperçu de mon code (pas trop non plus, il fait à peu près 4000 lignes :-D):
Au passage, désolé, je ne sais pas comment mettre un spoiler...
Partie constantes :
La partie fonctions :
Dernière partie sur les objets (Je mets uniquement le cube) :
Je simplifie aussi en retirant les opérateurs pour les homothéties.
De plus, la fonction isOK (x) sert simplement à savoir si x est un réel positif différent de zéro (pour éviter que les petits malins ne s'amusent à mettre une arête négative au cube : - |)
La fonction trans (x) à été simplifiée et spécialisée en formated (x)
Vous voyez donc pourquoi le traitement des résultats des opérations de base me pose problème.
Il y en a une dernière pour charger un certain nombre de constantes mathématiques comme pi, e ou encore la masse du Soleil, d'un proton...
Pour obtenir un retour formaté (pour éviter les résultats du genre -0.000000000000001 ou (3j - 0), quoi), j'ai fait une fonction qui traite le nombre et le renvoie bien propre et arrondi au nombre de décimales qu'on lui a demandé.
C'est la fonction trans (x) qu'on retrouve souvent.
Je ne vais pas mettre son code ici, ce serait inutile, en plus, il est moche : - )
Voilà un aperçu de mon code (pas trop non plus, il fait à peu près 4000 lignes :-D):
Au passage, désolé, je ne sais pas comment mettre un spoiler...
Partie constantes :
pi = 3.141592653589793238462 e = 2.71828182845904523536 phi = 1.618033988749894848204 G = 6.6743015e-11 i = 1j j = 1j c = 299792458 E = 1.602176634e-19 # Plus loin... # Je ne mets qu'une seule classe, il en a trois, mais elles fonctionnent de la même façon class MeasuresConstants: # In meters def __init__ (self): self._inch = 0.0254 # Le programme stocke les valeurs exactes et les renvoie formatées à la demande avec des property self._foot = 0.3048 self._yard = 0.9144 self._nauticalMile = 1852 self._league = 4828.032 self._ua = 149597870000 self._ly = 9460730472580800 self._parsec = 30856775670528308 def _getInch (self): return trans (self._inch) # Valeur de retour formatée def _getFoot (self): return trans (self._foot) def _getYard (self): return trans (self._yard) def _getNauticalMile (self): return trans (self._nauticalMile) def _getLeague (self): return trans (self._league) def _getUa (self): return trans (self._ua) def _getLy (self): return trans (self._ly) def _getParsec (self): return trans (self._parsec) def _setSomething (self, nValue): # On ne peut rien changer ici, on se fait donc gronder si on tente de modifier quoi que ce soit ! print ("\n You aren't allowed to change a constant value !\n") inch = property (_getInch, _setSomething) foot = property (_getFoot, _setSomething) yard = property (_getYard, _setSomething) nauticalMile = property (_getNauticalMile, _setSomething) league = property (_getLeague, _setSomething) ua = property (_getUa, _setSomething) ly = property (_getLy, _setSomething) parsec = property (_getParsec, _setSomething) m = MeasuresConstants (); # L'utilisateur y accède par m.nom_de_la_constante
La partie fonctions :
def frequence (duration, t = 1): # Renvoie une fréquence à partir d'une période et du nombre de répétitions dans cette période return trans (1 / (duration / t)) def sRadius (x): # Renvoie le rayon de Schwarzschild d'un trou noir en mètres return trans ((2 * 6.67408e-11 * x) / 299792458**2) def average (*params): # Revoie la moyenne de ses arguments values = list (params) summ = 0 i = len (values) - 1 while i > -1: summ += values[i] i -= 1 return trans (summ / len (values))
Dernière partie sur les objets (Je mets uniquement le cube) :
Je simplifie aussi en retirant les opérateurs pour les homothéties.
De plus, la fonction isOK (x) sert simplement à savoir si x est un réel positif différent de zéro (pour éviter que les petits malins ne s'amusent à mettre une arête négative au cube : - |)
La fonction trans (x) à été simplifiée et spécialisée en formated (x)
class Cube: def __init__ (self, edge = 1): # Quand on créé le cube if isOK (edge): self._edge = edge else: print ("\n Invalid edge : it must be a positive non-zero real number !\n Initialization of default values...\n Done\n") self._edge = 1 def _getEdge (self): return formated (self._edge) # Retour formaté def _getVolume (self): return formated (self._edge**3) def _getSurface (self): return formated (self._edge**2 * 6) def _getDiagonale (self): return formated (self._edge * 1.732050807568878) def _setEdge (self, nEdge): # Quand on veut changer l'arête du cube if isOK (nEdge): self._edge = nEdge else: print ("\n Invalid new edge : it must be a positive non-zero real number !\n") def _setVolume (self, nVolume): if isOK (nVolume): self._edge = nVolume**(1 / 3) else: print ("\n Invalid new volume : it must be a positive non-zero real number !\n") def _setSurface (self, nSurface): if isOK (nSurface): self._edge = (nSurface / 6)**0.5 else: print ("\n Invalid new surface : it must be a positive non-zero real number !\n") def _setDiagonale (self, nDiadonale): if isOK (nDiagonale): self._edge = nDiadonale / 1.732050807568878 else: print ("\n Invalid new diagonale : it must be a positive non-zero real number !\n") def __getattr__ (self, name): # Si l'utilisateur essaie d'accéder à un attribut qui n'existe pas print ("\n I'm so sorry, but there's no attribute named \"{}\" in this object !\n".format (name)) def __repr__ (self): # Lance une représentation graphique du cube print ("\n Loading resources...") system ('Graphics.pyw cube {0} {1} {2} {3}'.format (self.edge, self.volume, self.surface, self.diagonale)) return "\n Done !\n" edge = property (_getEdge, _setEdge) volume = property (_getVolume, _setVolume) surface = property (_getSurface, _setSurface) diagonale = property (_getDiagonale, _setDiagonale)
Vous voyez donc pourquoi le traitement des résultats des opérations de base me pose problème.
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
MemeTech
Messages postés
90
Date d'inscription
mercredi 14 août 2019
Statut
Membre
Dernière intervention
7 janvier 2021
1
2 nov. 2019 à 14:21
2 nov. 2019 à 14:21
Merci pour votre réponse !
En effet, votre méthode paraît tout à fait logique, mais comment faire pour éviter au pauvre utilisateur de se coltiner l'écriture :
>>> Int (5) + Float (6.9)
Merci !
En effet, votre méthode paraît tout à fait logique, mais comment faire pour éviter au pauvre utilisateur de se coltiner l'écriture :
>>> Int (5) + Float (6.9)
Merci !
MemeTech
Messages postés
90
Date d'inscription
mercredi 14 août 2019
Statut
Membre
Dernière intervention
7 janvier 2021
1
Modifié le 2 nov. 2019 à 15:10
Modifié le 2 nov. 2019 à 15:10
Justement, j'aimerais faire cela MAIS :
Pour faire une interface, ça va.
Par contre, pour interpréter les commandes de l'utilisateur, c'est un foutoir incroyable :
il y a deux fonctions pour éxécuter une commande Python : exec (cmd) et eval (cmd).
Il faut faire un mélange fumeux des deux car eval () fonctionnera bien pour les opérations,
exec () pour la création des objets...
Bref, entre les exeptions et les bugs incompréhensibles, je ne m'y retrouve pas.
Peut-être existe-il une fonction plus universelle pour cela ?
Pour faire une interface, ça va.
Par contre, pour interpréter les commandes de l'utilisateur, c'est un foutoir incroyable :
il y a deux fonctions pour éxécuter une commande Python : exec (cmd) et eval (cmd).
Il faut faire un mélange fumeux des deux car eval () fonctionnera bien pour les opérations,
exec () pour la création des objets...
Bref, entre les exeptions et les bugs incompréhensibles, je ne m'y retrouve pas.
Peut-être existe-il une fonction plus universelle pour cela ?
khrug
>
MemeTech
Messages postés
90
Date d'inscription
mercredi 14 août 2019
Statut
Membre
Dernière intervention
7 janvier 2021
2 nov. 2019 à 15:47
2 nov. 2019 à 15:47
Je ne comprends pas de quoi tu parles pour la création des objets, objets de quoi ?
MemeTech
Messages postés
90
Date d'inscription
mercredi 14 août 2019
Statut
Membre
Dernière intervention
7 janvier 2021
1
2 nov. 2019 à 16:58
2 nov. 2019 à 16:58
khrug
>
MemeTech
Messages postés
90
Date d'inscription
mercredi 14 août 2019
Statut
Membre
Dernière intervention
7 janvier 2021
3 nov. 2019 à 10:44
3 nov. 2019 à 10:44
Bonjour,
Je ne connais pas nyanmaths (c'est un module python ? une app externe ?), mais ça ne change pas grand chose à l'histoire, soit tu laisses l'utilisateur en roue libre, soit tu implémentes tout un tas de fonctionnalités via une interface graphique et là c'est un sacré boulot qui va demander beaucoup de temps.
Je ne connais pas nyanmaths (c'est un module python ? une app externe ?), mais ça ne change pas grand chose à l'histoire, soit tu laisses l'utilisateur en roue libre, soit tu implémentes tout un tas de fonctionnalités via une interface graphique et là c'est un sacré boulot qui va demander beaucoup de temps.
MemeTech
Messages postés
90
Date d'inscription
mercredi 14 août 2019
Statut
Membre
Dernière intervention
7 janvier 2021
1
3 nov. 2019 à 15:33
3 nov. 2019 à 15:33
Bon, après un certain nombre de tests et de bidouillages, j'ai l'impression que tout est ok !
Je mets le sujet en résolu dans deux jours si tout va bien et si personne n'a d'idées en plus pour améliorer la chose.
Merci encore pour votre aide !
Je mets le sujet en résolu dans deux jours si tout va bien et si personne n'a d'idées en plus pour améliorer la chose.
Merci encore pour votre aide !
2 nov. 2019 à 14:23
2 nov. 2019 à 14:46
En effet, pas bête, peut-être en contrôlant ce qui est donné en entrée ou fait en sortie avec sys.stdin et sys.stdout, mais je ne sais pas si c'est possible de le faire dans l'interpréteur python, il faudrait tester ^^
2 nov. 2019 à 14:31
Il me semblait que j'avais bien évité ce genre de choses, pourtant...
2 nov. 2019 à 15:46
par exemple sqrt(sqrt(2)), pourquoi arrondir deux fois?
quand tu fais sqrt(2)*1000, à quel moment veux-tu arrondir?
2 nov. 2019 à 15:50