Il existe déjà un module fractions en Python très bien fait, mais nous allons ici reconstruire petit à petit un équivalent.
Dans le cas de nos fractions, on veut définir une classe Fraction. Une fraction a/b est composée d'un numérateur entier a et d'un dénominateur entier b. On va donc définir deux attributs pour toutes les fractions, qui seront num et denom (pour aller plus vite), qui correspondront respectivement au numérateur et au dénominateur.
__init__ de la classe Fraction qui permettra de définir des fractions.__repr__ pour qu'elle renvoie une fraction sous la forme "numerateur / denominateur" (avec un espace entre pour mieux voir).Maintenant que nos fractions s'affichent correctement et avant de s'attaquer aux opérations entre fractions, il va falloir s'intéresser à comment les réduire. Pour réduire une fraction, il suffit de diviser le numérateur et le dénominateur par le pgcd des deux. Pour obtenir le pgcd, on utilisera la fonction gcd du module math.
reduire() qui renvoie la fraction réduite.__str__ pour qu'elle affiche seulement le numérateur lorsque le dénominateur est 1 (donc quand on a un nombre entier).Revenons un peu sur la façon de construire un élément de notre classe. Au début on a simplement créé la méthode __init__ qui permet, lorsqu'on écrit Fraction(2,3), de créer un élément ayant 2 attributs : un qui s'appelle num et qui ici vaut 2, et un qui s'appelle denom et qui prend la valeur 3.
On va s'intéresser, en plus, au signe de notre fraction : on sait que -2/3 = 2/-3 = -(2/3). Pour simplifier les choses et éviter de voir s'afficher des fractions sous la forme "2 / -3" ou "-2 / -3", on va systématiquement mettre le signe - (s'il y est encore après simplification) au numérateur, et cela dès la création de la Fraction, c'est-à-dire dans la fonction __init__.
De plus, il est impossible de créer une fraction ayant un 0 comme dénominateur, donc si c'est le cas, on va lever une exception. Pour cela il suffit de tester la valeur de b et, si b est nul, écrire raise ZeroDivisionError pour que s'affiche un message rouge lorsqu'on met 0 en dénominateur.
En testant Fraction(1,2)==Fraction(1,2), le résultat obtenu est False au lieu de True.
Pour nous les fractions sont les mêmes, mais pour Python ce sont deux objets différents. Il faut donc expliquer ce que Python doit comprendre par "deux Fractions égales".
Pour cela, on va utiliser la méthode spéciale __eq__. Cette méthode (surcharge d'opérateur) doit renvoyer True quand elles sont égales et False sinon (donc quand on utilise ==).
a/b = c/d si et seulement si a×d = b×c
Expliquons ce que doit comprendre Python lorsqu'on écrit Fraction(1,3) < Fraction(1,2).
Pour l'inégalité stricte "<", il faut utiliser la méthode __lt__ (lt pour less than).
Pour l'inégalité large "<=", il faut utiliser la méthode __le__. Pas besoin de redéfinir (mais on pourrait) les méthodes pour ">" et ">=" car elles sont automatiquement déduites des deux précédentes (tout comme != se déduit de ==).
Créer les 2 méthodes précédentes. Pour cela, on rappelle que : si bd > 0 alors a/b < c/d ⇔ ad < bc
On voudrait que lorsqu'on tape Fraction(1,3)+Fraction(1,3) on obtienne Fraction(2,3), et tant qu'à faire ce serait bien qu'on obtienne la forme simplifiée réduite. Pour cela, il faut utiliser la méthode __add__.
a/b + c/d = (ad + bc) / bd
Il reste maintenant à utiliser les méthodes (surcharges d'opérateurs) __sub__, __mul__ et __truediv__, qui correspondent respectivement à la soustraction, la multiplication et la division, et toutes les opérations sur les fractions seront prises en compte.