Python pas cher
- 5 conseils pour booster les conversions de formulaires pour WordPress
- Episode # 39 Obtenir votre premier emploi de développeur en tant que développeur Python (partie 1)
- Épisode # 246 Pratiques du Python Pro
- Comprendre is_singular dans les modèles WordPress • WPShout
- Extraire les valeurs des itérables – Real Python
Python prend en charge un large éventail d'opérateurs arithmétiques que vous pouvez utiliser lorsque vous travaillez avec des nombres dans votre code. L'un de ces opérateurs est le opérateur modulo (%
), qui renvoie le reste de la division de deux nombres.
L'opérateur modulo Python peut parfois être négligé. Mais avoir une bonne compréhension de cet opérateur vous donnera un outil précieux dans votre ceinture d'outils Python.
Modulo en mathématiques
Le terme modulo provient d'une branche des mathématiques appelée arithmétique modulaire. L'arithmétique modulaire traite de l'arithmétique des nombres entiers sur une droite numérique circulaire qui a un ensemble fixe de nombres. Toutes les opérations arithmétiques effectuées sur cette droite numérique s'enrouleront lorsqu'elles atteindront un certain nombre appelé le module.
Un exemple classique de modulo en arithmétique modulaire est l'horloge de douze heures. Une horloge de douze heures a un ensemble fixe de valeurs, de 1 à 12. Lorsque vous comptez sur une horloge de douze heures, vous comptez jusqu'au module 12, puis revenez à 1. Une horloge de douze heures peut être classée comme " modulo 12 », parfois abrégé en« mod 12. »
L'opérateur modulo est utilisé lorsque vous souhaitez comparer un nombre avec le module et obtenir le nombre équivalent contraint à la plage du module.
Par exemple, supposons que vous souhaitiez déterminer l'heure à laquelle il serait neuf heures après 8h00. Sur une horloge de douze heures, vous ne pouvez pas simplement ajouter 9 à 8 car vous obtiendriez 17. Vous devez prendre le résultat, 17 , et utilise mod
pour obtenir sa valeur équivalente dans un contexte de douze heures:
8 heures + 9 = 17 heures
17 mod 12 = 5
17 mod 12
Retour 5
. Cela signifie que neuf heures après 8h00, c'est 17h00. Vous avez déterminé cela en prenant le nombre 17
et l'appliquer à un mod 12
le contexte.
Maintenant, si vous y pensez, 17
et 5
sont équivalents dans un mod 12
le contexte. Si vous regardiez l'aiguille des heures à 5 h et 17 h, elle serait dans la même position. L'arithmétique modulaire a une équation pour décrire cette relation:
Cette équation dit "une
et b
sont modulo congruents n
. » Cela signifie que une
et b
sont équivalents en mod n
car ils ont le même reste lorsqu'ils sont divisés par n
. Dans l'équation ci-dessus, n
est le module pour les deux une
et b
. Utiliser les valeurs 17
et 5
d'avant, l'équation ressemblerait à ceci:
Cela se lit "17
et 5
sont modulo congruents 12
. » 17
et 5
avoir le même reste, 5
, lorsqu'il est divisé par 12
. Donc dans mod 12
, les nombres 17
et 5
sont équivalents.
Vous pouvez le confirmer en utilisant la division:
17/12 = 1 R 5
5/12 = 0 R 5
Les deux opérations ont le même reste, 5
, donc ils sont équivalents modulo 12
.
Maintenant, cela peut sembler beaucoup de maths pour un opérateur Python, mais avoir ces connaissances vous préparera à utiliser l'opérateur modulo dans les exemples plus loin dans ce tutoriel. Dans la section suivante, vous examinerez les bases de l'utilisation de l'opérateur modulo Python avec les types numériques int
et flotte
.
Principes de base de l'opérateur Python Modulo
L'opérateur modulo, comme les autres opérateurs arithmétiques, peut être utilisé avec les types numériques int
et flotte
. Comme vous le verrez plus tard, il peut également être utilisé avec d'autres types comme math.fmod ()
, décimal.Décimal
et vos propres classes.
Opérateur Modulo avec int
La plupart du temps, vous utiliserez l'opérateur modulo avec des entiers. L'opérateur modulo, lorsqu'il est utilisé avec deux entiers positifs, retournera le reste de la division euclidienne standard:
>>> 15 % 4
3
>>> 17 % 12
5
>>> 240 % 13
6
>>> dix % 16
dix
Faites attention! Tout comme avec l'opérateur de division (/
), Python renverra un ZeroDivisionError
si vous essayez d'utiliser l'opérateur modulo avec un diviseur de 0
:
>>> 22 % 0
ZeroDivisionError: division entière ou modulo par zéro
Ensuite, vous allez examiner l'utilisation de l'opérateur modulo avec un flotte
.
Opérateur Modulo avec flotte
Semblable à int
, l'opérateur modulo utilisé avec un flotte
renverra le reste de la division, mais comme un flotte
valeur:
>>> 12,5 % 5.5
1,5
>>> 17,0 % 12,0
5,0
Une alternative à l'utilisation d'un flotte
avec l'opérateur modulo est d'utiliser math.fmod ()
pour effectuer des opérations modulo sur flotte
valeurs:
>>> importer math
>>> math.fmod(12,5, 5.5)
1,5
>>> math.fmod(8,5, 2,5)
1.0
Les documents officiels Python suggèrent d'utiliser math.fmod ()
sur l'opérateur modulo Python lorsque vous travaillez avec flotte
valeurs à cause de la manière math.fmod ()
calcule le résultat de l'opération modulo. Si vous utilisez un opérande négatif, vous pouvez voir des résultats différents entre math.fmod (x, y)
et x% y
. Vous découvrirez l'utilisation de l'opérateur modulo avec des opérandes négatifs plus en détail dans la section suivante.
Tout comme les autres opérateurs arithmétiques, l'opérateur modulo et math.fmod ()
peut rencontrer des problèmes d'arrondi et de précision lors du traitement de l'arithmétique à virgule flottante:
>>> 13,3 % 1.1
0,09999999999999964
>>> importer math
>>> math.fmod(13,3, 1.1)
0,09999999999999964
Si le maintien de la précision en virgule flottante est important pour votre application, vous pouvez utiliser l'opérateur modulo avec décimal.Décimal
. Vous y reviendrez plus tard dans ce didacticiel.
Opérateur modulo avec un opérande négatif
Toutes les opérations modulo que vous avez vues jusqu'à présent ont utilisé deux opérandes positifs et ont renvoyé des résultats prévisibles. Lorsqu'un opérande négatif est introduit, les choses se compliquent.
En fait, la façon dont les ordinateurs déterminent le résultat d'une opération modulo avec un opérande négatif laisse une ambiguïté quant à savoir si le reste doit prendre le signe du dividende (le nombre étant divisé) ou le signe du diviseur (le nombre par lequel le dividende est divisé). Différents langages de programmation gèrent cela différemment.
Par exemple, en JavaScript, le reste prendra le signe du dividende:
Le reste dans cet exemple, 2
, est positif car il prend le signe du dividende, 8
. En Python et dans d'autres langages, le reste prendra le signe du diviseur à la place:
Ici vous pouvez voir que le reste, -1
, prend le signe du diviseur, -3
.
Vous vous demandez peut-être pourquoi le reste en JavaScript est 2
et le reste en Python est -1
. Cela a à voir avec la façon dont différentes langues déterminent le résultat d'une opération modulo. Les langues dans lesquelles le reste prend le signe du dividende utilisent l'équation suivante pour déterminer le reste:
Il y a trois variables cette équation:
r
est le reste.une
est le dividende.n
est le diviseur.
tronc ()
dans cette équation signifie qu'il utilise division tronquée, qui arrondira toujours un nombre négatif vers zéro. Pour plus de précisions, voir les étapes de l'opération modulo ci-dessous en utilisant 8
comme dividende et -3
comme diviseur:
r = 8 - (-3 * tronc (8 / -3))
r = 8 - (-3 * tronc (-2,666666666667))
r = 8 - (-3 * -2) # Arrondi vers 0
r = 8 - 6
r = 2
Ici, vous pouvez voir comment un langage comme JavaScript obtient le reste 2
. Python et d'autres langages dans lesquels le reste prend le signe du diviseur utilisent l'équation suivante:
sol()
dans cette équation signifie qu'il utilise division de plancher. Avec des nombres positifs, la division de plancher renverra le même résultat que la division tronquée. Mais avec un nombre négatif, la division par étage arrondira le résultat vers le bas, loin de zéro:
r = 8 - (-3 * plancher (8 / -3))
r = 8 - (-3 * plancher (-2,666666666667))
r = 8 - (-3 * -3) # Arrondi à partir de 0
r = 8 - 9
r = -1
Ici, vous pouvez voir que le résultat est -1
.
Maintenant que vous comprenez d'où vient la différence dans le reste, vous vous demandez peut-être pourquoi cela est important si vous n'utilisez que Python. Eh bien, il s'avère que toutes les opérations modulo en Python ne sont pas identiques. Alors que le modulo utilisé avec le int
et flotte
les types prendront le signe du diviseur, les autres types non.
Vous pouvez voir un exemple de ceci lorsque vous comparez les résultats de 8,0% -3,0
et math.fmod (8.0, -3.0)
:
>>> 8,0 % -3
-1,0
>>> importer math
>>> math.fmod(8,0, -3.0)
2.0
math.fmod ()
prend le signe du dividende en utilisant une division tronquée, alors que flotte
utilise le signe du diviseur. Plus loin dans ce didacticiel, vous verrez un autre type Python qui utilise le signe du dividende, décimal.Décimal
.
Opérateur Modulo et divmod ()
Python a la fonction intégrée divmod ()
, qui utilise en interne l'opérateur modulo. divmod ()
prend deux paramètres et retourne un tuple contenant les résultats de la division de plancher et modulo en utilisant les paramètres fournis.
Voici un exemple d'utilisation divmod ()
avec 37
et 5
:
>>> divmod(37, 5)
(7, 2)
>>> 37 // 5
7
>>> 37 % 5
2
Tu peux voir ça divmod (37, 5)
renvoie le tuple (7, 2)
. le 7
est le résultat de la division par étage de 37
et 5
. le 2
est le résultat de 37
modulo 5
.
Voici un exemple dans lequel le deuxième paramètre est un nombre négatif. Comme indiqué dans la section précédente, lorsque l'opérateur modulo est utilisé avec un int
, le reste prendra le signe du diviseur:
>>> divmod(37, -5)
(-8, -3)
>>> 37 // -5
-8
>>> 37 % -5
-3 # Le résultat a le signe du diviseur
Maintenant que vous avez eu la chance de voir l'opérateur modulo utilisé dans plusieurs scénarios, il est important de regarder comment Python détermine la priorité de l'opérateur modulo lorsqu'il est utilisé avec d'autres opérateurs arithmétiques.
Préséance des opérateurs modulo
Comme les autres opérateurs Python, il existe des règles spécifiques pour l'opérateur modulo qui déterminent sa priorité lors de l'évaluation des expressions. L'opérateur modulo (%
) partage le même niveau de priorité que la multiplication (*
), division (/
) et la division au sol (//
) les opérateurs.
Jetez un œil à un exemple de priorité de l'opérateur modulo ci-dessous:
>>> 4 * dix % 12 - 9
-5
Les opérateurs de multiplication et modulo ont le même niveau de priorité, donc Python les évaluera de gauche à droite. Voici les étapes de l'opération ci-dessus:
4 * 10
est évalué, ce qui entraîne40% 12 - 9
.40% 12
est évalué, ce qui entraîne4 - 9
.4 - 9
est évalué, ce qui entraîne-5
.
Si vous souhaitez remplacer la priorité des autres opérateurs, vous pouvez utiliser des parenthèses pour entourer l'opération que vous souhaitez évaluer en premier:
>>> 4 * dix % (12 - 9)
1
Dans cet exemple, (12 - 9)
est évalué en premier, suivi de 4 * 10
et enfin 40% 3
, qui équivaut à 1
.
Opérateur Modulo Python en pratique
Maintenant que vous avez parcouru les bases de l'opérateur modulo Python, vous allez examiner quelques exemples d'utilisation de celui-ci pour résoudre des problèmes de programmation réels. Parfois, il peut être difficile de déterminer quand utiliser l'opérateur modulo dans votre code. Les exemples ci-dessous vous donneront une idée des nombreuses façons dont il peut être utilisé.
Comment vérifier si un nombre est pair ou impair
Dans cette section, vous verrez comment utiliser l’opérateur modulo pour déterminer si un nombre est pair ou impair. Utilisation de l'opérateur modulo avec un module de 2
, vous pouvez vérifier n'importe quel nombre pour voir s'il est divisible par 2
. S'il est divisible de manière égale, il s'agit d'un nombre pair.
Jeter un coup d'œil à est même()
qui vérifie si le num
le paramètre est pair:
def est même(num):
revenir num % 2 == 0
Ici num% 2
sera égal 0
si num
est pair et 1
si num
est impair. Vérification contre 0
renverra un booléen de Vrai
ou Faux
selon que oui ou non num
est même.
La vérification des nombres impairs est assez similaire. Pour vérifier un nombre impair, vous inversez le contrôle d'égalité:
def est impair(num):
revenir num % 2 ! = 0
Cette fonction retournera Vrai
si num% 2
n'est pas égal 0
, ce qui signifie qu'il y a un reste prouvant num
est un nombre impair. Maintenant, vous vous demandez peut-être si vous pouvez utiliser la fonction suivante pour déterminer si num
est un nombre impair:
def est impair(num):
revenir num % 2 == 1
La réponse à cette question est oui et non. Techniquement, cette fonction fonctionnera avec la façon dont Python calcule modulo avec des entiers. Cela dit, évitez de comparer le résultat d'une opération modulo avec 1
car toutes les opérations modulo en Python ne renverront pas le même reste.
Vous pouvez voir pourquoi dans les exemples suivants:
>>> -3 % 2
1
>>> 3 % -2
-1
Dans le deuxième exemple, le reste prend le signe du diviseur négatif et renvoie -1
. Dans ce cas, la vérification booléenne 3% -2 == 1
retournerais Faux
.
Cependant, si vous comparez l'opération modulo avec 0
, alors peu importe quel opérande est négatif. Le résultat sera toujours Vrai
lorsqu'il s'agit d'un nombre pair:
>>> -2 % 2
0
>>> 2 % -2
0
Si vous vous en tenez à comparer une opération modulo Python avec 0
, alors vous ne devriez pas avoir de problèmes pour vérifier les nombres pairs et impairs ou tout autre multiple d'un nombre dans votre code.
Dans la section suivante, vous découvrirez comment vous pouvez utiliser l'opérateur modulo avec des boucles pour contrôler le flux de votre programme.
Comment exécuter du code à des intervalles spécifiques dans une boucle
Avec l'opérateur modulo Python, vous pouvez exécuter du code à des intervalles spécifiques dans une boucle. Cela se fait en effectuant une opération modulo avec l'indice actuel de la boucle et un module. Le numéro de module détermine la fréquence à laquelle le code spécifique à l'intervalle s'exécutera dans la boucle.
Voici un exemple:
def split_names_into_rows(liste de nom, module=3):
pour indice, Nom dans énumérer(liste de nom, début=1):
impression(F"Nom:- ^ 15 ", fin="")
si indice % module == 0:
impression()
impression()
Ce code définit split_names_into_rows ()
, qui prend deux paramètres. liste de nom
est une liste de noms qui doivent être divisés en lignes. module
définit un module pour l'opération, déterminant effectivement le nombre de noms devant figurer dans chaque ligne. split_names_into_rows ()
bouclera liste de nom
et commencez une nouvelle ligne après avoir atteint le module
valeur.
Avant de décomposer la fonction plus en détail, regardez-la en action:
>>> des noms = [[[["Picard", "Riker", "Troi", "Broyeur", "Worf", "Les données", "La Forge"]
>>> split_names_into_rows(des noms)
---- Picard ----- ----- Riker ----- ----- Troi ------
---- Concasseur ---- ----- Worf ------ ----- Données ------
--- La Forge ----
Comme vous pouvez le voir, la liste des noms a été divisée en trois lignes, avec un maximum de trois noms dans chaque ligne. module
par défaut 3
, mais vous pouvez spécifier n'importe quel nombre:
>>> split_names_into_rows(des noms, module=4)
---- Picard ----- ----- Riker ----- ----- Troi ------ ---- Concasseur ----
----- Worf ------ ----- Données ------ --- La Forge ----
>>> split_names_into_rows(des noms, module=2)
---- Picard ----- ----- Riker -----
----- Troi ------ ---- Concasseur ----
----- Worf ------ ----- Données ------
--- La Forge ----
>>> split_names_into_rows(des noms, module=1)
---- Picard -----
----- Riker -----
----- Troi ------
----Broyeur----
----- Worf ------
-----Les données------
--- La Forge ----
Maintenant que vous avez vu le code en action, vous pouvez décomposer ce qu’il fait. Premièrement, il utilise énumérer
itérer sur liste de nom
, affectant l'élément actuel de la liste à Nom
et une valeur de comptage à indice
. Vous pouvez voir que l'option début
argument pour énumérer
est réglé sur 1
. Cela signifie que le indice
le compte commencera à 1
au lieu de 0
:
pour indice, Nom dans énumérer(liste de nom, début=1):
Ensuite, à l'intérieur de la boucle, la fonction appelle impression()
pour sortir Nom
à la ligne actuelle. le fin
paramètre pour impression()
est une chaîne vide (""
) afin qu'il ne génère pas de nouvelle ligne à la fin de la chaîne. Une f-string est passée à impression()
, qui utilise la syntaxe de formatage de sortie de chaîne fournie par Python:
impression(F"Nom:- ^ 15 ", fin="")
Sans entrer dans les détails, le : - ^ 15
la syntaxe dit impression()
pour faire ce qui suit:
- Sortie au moins
15
caractères, même si la chaîne est inférieure à 15 caractères. - Alignez la chaîne au centre.
- Remplissez n'importe quel espace à droite ou à gauche de la chaîne avec le trait d'union (
-
).
Maintenant que le nom a été imprimé sur la ligne, jetez un œil à la partie principale de split_names_into_rows ()
:
si indice % module == 0:
impression()
Ce code prend l'itération actuelle indice
et, en utilisant l'opérateur modulo, le compare avec module
. Si le résultat est égal à 0
, puis il peut exécuter du code spécifique à l'intervalle. Dans ce cas, la fonction appelle impression()
pour ajouter une nouvelle ligne, qui commence une nouvelle ligne.
Le code ci-dessus n'est qu'un exemple. Utilisation du motif indice% module == 0
vous permet d'exécuter différents codes à des intervalles spécifiques dans vos boucles. Dans la section suivante, vous allez pousser ce concept un peu plus loin et examiner l'itération cyclique.
Comment créer une itération cyclique
Itération cyclique décrit un type d'itération qui se réinitialisera une fois atteint un certain point. Généralement, ce type d'itération est utilisé pour restreindre l'index de l'itération à une certaine plage.
Vous pouvez utiliser l'opérateur modulo pour créer une itération cyclique. Jetez un œil à un exemple utilisant le tortue
bibliothèque pour dessiner une forme:
importer tortue
importer Aléatoire
def draw_with_cyclic_iteration():
couleurs = [[[["vert", "cyan", "Orange", "violet", "rouge", "Jaune", "blanc"]
tortue.bgcolor("gray8") # Hex: # 333333
tortue.pendre()
tortue.couleur de crayon(Aléatoire.choix(couleurs)) # La première couleur est aléatoire
je = 0 # Index initial
tandis que Vrai:
je = (je + 1) % 6 # Mettre à jour l'index
tortue.penser(je) # Définir la taille du stylo sur i
tortue.vers l'avant(225)
tortue.droite(170)
# Choisissez une couleur aléatoire
si je == 0:
tortue.couleur de crayon(Aléatoire.choix(couleurs))
Le code ci-dessus utilise une boucle infinie pour dessiner une forme d'étoile répétitive. Toutes les six itérations, il change la couleur du stylo. La taille du stylo augmente à chaque itération jusqu'à je
est réinitialisé à 0
. Si vous exécutez le code, vous devriez obtenir quelque chose de similaire à ceci:
Les parties importantes de ce code sont mises en évidence ci-dessous:
importer tortue
importer Aléatoire
def draw_with_cyclic_iteration():
couleurs = [[[["vert", "cyan", "Orange", "violet", "rouge", "Jaune", "blanc"]
tortue.bgcolor("gray8") # Hex: # 333333
tortue.pendre()
tortue.couleur de crayon(Aléatoire.choix(couleurs))
je = 0 # Index initial
tandis que Vrai:
je = (je + 1) % 6 # Mettre à jour l'index
tortue.penser(je) # Définir la taille du stylo sur i
tortue.vers l'avant(225)
tortue.droite(170)
# Choisissez une couleur aléatoire
si je == 0:
tortue.couleur de crayon(Aléatoire.choix(couleurs))
À chaque fois dans la boucle, je
est mis à jour en fonction des résultats de (i + 1)% 6
. Cette nouvelle je
valeur est utilisée pour augmenter la .pensize
à chaque itération. Une fois que je
atteint 5
, (i + 1)% 6
sera égal 0
, et je
sera réinitialisé à 0
.
Vous pouvez voir les étapes de l'itération ci-dessous pour plus de précisions:
i = 0: (0 + 1)% 6 = 1
i = 1: (1 + 1)% 6 = 2
i = 2: (2 + 1)% 6 = 3
i = 3: (3 + 1)% 6 = 4
i = 4: (4 + 1)% 6 = 5
i = 5: (5 + 1)% 6 = 0 # Réinitialiser
Quand je
est réinitialisé à 0
, le .pencolor
change à une nouvelle couleur aléatoire comme indiqué ci-dessous:
si je == 0:
tortue.couleur de crayon(Aléatoire.choix(couleurs))
Le code de cette section utilise 6
comme module, mais vous pouvez le définir sur n'importe quel nombre pour ajuster le nombre d'itérations de la boucle avant de réinitialiser la valeur je
.
Comment convertir des unités
Dans cette section, vous allez voir comment vous pouvez utiliser l'opérateur modulo pour convertir des unités. Les exemples suivants prennent des unités plus petites et les convertissent en unités plus grandes sans utiliser de décimales. L'opérateur modulo est utilisé pour déterminer tout reste qui peut exister lorsque l'unité la plus petite n'est pas divisible uniformément par l'unité la plus grande.
Dans ce premier exemple, vous allez convertir des pouces en pieds. L'opérateur modulo est utilisé pour obtenir les pouces restants qui ne se divisent pas uniformément en pieds. L'opérateur de division d'étage (//
) est utilisé pour arrondir le total des pieds:
def convert_inches_to_feet(total_inches):
pouces = total_inches % 12
pieds = total_inches // 12
impression(F"total_inches pouces = pieds pieds et pouces pouces")
Voici un exemple de la fonction utilisée:
>>> convert_inches_to_feet(450)
450 pouces = 37 pieds et 6 pouces
Comme vous pouvez le voir sur la sortie, 450% 12
Retour 6
, qui sont les pouces restants qui n’ont pas été divisés en pieds. Le résultat de 450 // 12
est 37
, qui est le nombre total de pieds par lequel les pouces ont été répartis également.
Vous pouvez aller un peu plus loin dans cet exemple suivant. convert_minutes_to_days ()
prend un entier, total_mins
, représentant un nombre de minutes et affiche la période en jours, heures et minutes:
def convert_minutes_to_days(total_mins):
journées = total_mins // 1440
extra_minutes = total_mins % 1440
heures = extra_minutes // 60
minutes = extra_minutes % 60
impression(F"total_mins = journées journées, heures heures, et minutes minutes")
En décomposant cela, vous pouvez voir que la fonction effectue les opérations suivantes:
- Détermine le nombre total de jours divisibles uniformément avec
total_mins // 1440
, où1440
est le nombre de minutes dans une journée - Calcule tout
extra_minutes
laissé avectotal_mins% 1440
- Utilise le
extra_minutes
pour obtenir le même divisibleheures
et tout extraminutes
Vous pouvez voir comment cela fonctionne ci-dessous:
>>> convert_minutes_to_days(1503)
1503 = 1 jour, 1 heure et 3 minutes
>>> convert_minutes_to_days(3456)
3456 = 2 jours, 9 heures et 36 minutes
>>> convert_minutes_to_days(35 000)
35000 = 24 jours, 7 heures et 20 minutes
Bien que les exemples ci-dessus ne traitent que de la conversion des pouces en pieds et des minutes en jours, vous pouvez utiliser n'importe quel type d'unités avec l'opérateur modulo pour convertir une unité plus petite en une unité plus grande.
Remarque: Les deux exemples ci-dessus peuvent être modifiés pour utiliser divmod ()
pour rendre le code plus succinct. Si tu te souviens, divmod ()
renvoie un tuple contenant les résultats de la division de plancher et du modulo en utilisant les paramètres fournis.
Ci-dessous, la division de plancher et les opérateurs modulo ont été remplacés par divmod ()
:
def convert_inches_to_feet_updated(total_inches):
pieds, pouces = divmod(total_inches, 12)
impression(F"total_inches pouces = pieds pieds et pouces pouces")
Comme vous pouvez le voir, divmod (total_inches, 12)
renvoie un tuple, qui est décompressé dans pieds
et pouces
.
Si vous essayez cette fonction mise à jour, vous obtiendrez les mêmes résultats qu'auparavant:
>>> convert_inches_to_feet(450)
450 pouces = 37 pieds et 6 pouces
>>> convert_inches_to_feet_updated(450)
450 pouces = 37 pieds et 6 pouces
Vous obtenez le même résultat, mais maintenant le code est plus concis. Vous pourriez mettre à jour convert_minutes_to_days ()
ainsi que:
def convert_minutes_to_days_updated(total_mins):
journées, extra_minutes = divmod(total_mins, 1440)
heures, minutes = divmod(extra_minutes, 60)
impression(F"total_mins = journées journées, heures heures, et minutes minutes")
En utilisant divmod ()
, la fonction est plus facile à lire que la version précédente et renvoie le même résultat:
>>> convert_minutes_to_days(1503)
1503 = 1 jour, 1 heure et 3 minutes
>>> convert_minutes_to_days_updated(1503)
1503 = 1 jour, 1 heure et 3 minutes
En utilisant divmod ()
n'est pas nécessaire dans toutes les situations, mais cela a du sens ici car les calculs de conversion d'unité utilisent à la fois la division du sol et le modulo.
Maintenant que vous avez vu comment utiliser l'opérateur modulo pour convertir des unités, dans la section suivante, vous allez voir comment vous pouvez utiliser l'opérateur modulo pour vérifier les nombres premiers.
Comment déterminer si un nombre est un nombre premier
Dans cet exemple suivant, vous allez voir comment vous pouvez utiliser l'opérateur modulo Python pour vérifier si un nombre est un nombre premier. Un nombre premier est un nombre qui ne contient que deux facteurs, 1
et lui-même. Quelques exemples de nombres premiers sont 2
, 3
, 5
, 7
, 23
, 29
, 59
, 83
, et 97
.
Le code ci-dessous est une implémentation pour déterminer la primalité d'un nombre à l'aide de l'opérateur modulo:
def check_prime_number(num):
si num < 2:
impression(F"num doit être supérieur ou égal à 2 pour être premier. ")
revenir
facteurs = [([([([(1, num)]
je = 2
tandis que je * je <= num:
si num % je == 0:
facteurs.ajouter((je, num//je))
je + = 1
si len(facteurs) > 1:
impression(F"num n'est pas primordial. Il a les facteurs suivants: facteurs")
autre:
impression(F"num est un nombre premier ")
Ce code définit check_prime_number ()
, qui prend le paramètre num
et vérifie s'il s'agit d'un nombre premier. Si tel est le cas, un message s'affiche indiquant que num
est un nombre premier. S'il ne s'agit pas d'un nombre premier, un message s'affiche avec tous les facteurs du nombre.
Remarque: Le code ci-dessus n'est pas le moyen le plus efficace de vérifier les nombres premiers. Si vous souhaitez creuser plus profondément, consultez le tamis d'Ératosthène et le tamis d'Atkin pour des exemples d'algorithmes plus performants pour trouver des nombres premiers.
Avant de regarder de plus près la fonction, voici les résultats en utilisant différents nombres:
>>> check_prime_number(44)
44 n'est pas premier. Il a les facteurs suivants: [(1, 44), (2, 22), (4, 11)]
>>> check_prime_number(53)
53 est un nombre premier
>>> check_prime_number(115)
115 n'est pas premier. Il a les facteurs suivants: [(1, 115), (5, 23)]
>>> check_prime_number(997)
997 est un nombre premier
En creusant dans le code, vous pouvez voir qu'il commence en vérifiant si num
est inférieur à 2
. Les nombres premiers ne peuvent être supérieurs ou égaux à 2
. Si num
est inférieur à 2
, la fonction n’a pas besoin de continuer. Ce sera impression()
un message et revenir
:
si num < 2:
impression(F"num doit être supérieur ou égal à 2 pour être premier. ")
revenir
Si num
est supérieur à 2
, alors la fonction vérifie si num
est un nombre premier. Pour vérifier cela, la fonction itère sur tous les nombres entre 2
et la racine carrée de num
pour voir si l'un se divise uniformément en num
. Si l'un des nombres se divise uniformément, un facteur a été trouvé, et num
ne peut pas être un nombre premier.
Voici la partie principale de la fonction:
facteurs = [([([([(1, num)]
je = 2
tandis que je * je <= num:
si num % je == 0:
facteurs.ajouter((je, num//je))
je + = 1
Il y a beaucoup de choses à déballer ici, alors allons-y étape par étape.
Tout d'abord, un facteurs
la liste est créée avec les facteurs initiaux, (1, num)
. Cette liste sera utilisée pour stocker tous les autres facteurs trouvés:
Ensuite, en commençant par 2
, le code s'incrémente je
jusqu'à ce qu'il atteigne la racine carrée de num
. À chaque itération, il compare num
avec je
pour voir s’il est divisible de manière égale. Le code doit uniquement vérifier jusqu'à et y compris la racine carrée de num
car il ne contiendrait aucun facteur supérieur à ceci:
je = 2
tandis que je * je <= num:
si num % je == 0:
facteurs.ajouter((je, num//je))
je + = 1
Au lieu d'essayer de déterminer la racine carrée de num
, la fonction utilise un tandis que
boucle pour voir si i * i <= num
. Aussi longtemps que i * i <= num
, la boucle n'a pas atteint la racine carrée de num
.
À l'intérieur de tandis que
boucle, l'opérateur modulo vérifie si num
est divisible par je
:
facteurs = [([([([(1, num)]
je = 2 # Démarrer l'index initial à 2
tandis que je * je <= num:
si num % je == 0:
facteurs.ajouter((je, num//je))
je + = 1
Si num
est divisible par je
, puis je
est un facteur de num
, et un tuple des facteurs est ajouté au facteurs
liste.
Une fois la tandis que
boucle est terminée, le code vérifie si des facteurs supplémentaires ont été trouvés:
si len(facteurs) > 1:
impression(F"num n'est pas primordial. Il a les facteurs suivants: facteurs")
autre:
impression(F"num est un nombre premier ")
If more than one tuple exists in the factors
list, then num
can’t be a prime number. For nonprime numbers, the factors are printed out. For prime numbers, the function prints a message stating that num
is a prime number.
How to Implement Ciphers
The Python modulo operator can be used to create ciphers. A cipher is a type of algorithm for performing encryption and decryption on an input, usually text. In this section, you’ll look at two ciphers, the Caesar cipher et le Vigenère cipher.
Caesar Cipher
The first cipher that you’ll look at is the Caesar cipher, named after Julius Caesar, who used it to secretly communicate messages. It’s a substitution cipher that uses letter substitution to encrypt a string of text.
The Caesar cipher works by taking a letter to be encrypted and shifting it a certain number of positions to the left or right in the alphabet. Whichever letter is in that position is used as the encrypted character. This same shift value is applied to all characters in the string.
For example, if the shift were 5
, then UNE
would shift up five letters to become F
, B
would become G
, and so on. Below you can see the encryption process for the text REALPYTHON
with a shift of 5
:
The resulting cipher is WJFQUDYMTS
.
Decrypting the cipher is done by reversing the shift. Both the encryption and decryption processes can be described with the following expressions, where char_index
is the index of the character in the alphabet:
encrypted_char_index = (char_index + shift) % 26
decrypted_char_index = (char_index - shift) % 26
This cipher uses the modulo operator to make sure that, when shifting a letter, the index will wrap around if the end of the alphabet is reached. Now that you know how this cipher works, take a look at an implementation:
import chaîne
def caesar_cipher(text, shift, decrypt=False):
si ne pas text.isascii() ou ne pas text.isalpha():
raise ValueError("Text must be ASCII and contain no numbers.")
lowercase = chaîne.ascii_lowercase
uppercase = chaîne.ascii_uppercase
result = ""
si decrypt:
shift = shift * -1
pour char dans text:
si char.islower():
index = lowercase.index(char)
result += lowercase[([([([(index + shift) % 26]
else:
index = uppercase.index(char)
result += uppercase[([([([(index + shift) % 26]
revenir result
This code defines a function called caesar_cipher()
, which has two required parameters and one optional parameter:
text
is the text to be encrypted or decrypted.shift
is the number of positions to shift each letter.decrypt
is a Boolean to set iftext
should be decrypted.
decrypt
is included so that a single function can be used to handle both encryption and decryption. This implementation can handle only alphabetic characters, so the function first checks that text
is an alphabetic character in the ASCII encoding:
def caesar_cipher(text, shift, decrypt=False):
si ne pas text.isascii() ou ne pas text.isalpha():
raise ValueError("Text must be ASCII and contain no numbers.")
The function then defines three variables to store the lowercase
ASCII characters, the uppercase
ASCII characters, and the results of the encryption or decryption:
lowercase = chaîne.ascii_lowercase # "abcdefghijklmnopqrstuvwxyz"
uppercase = chaîne.ascii_uppercase # "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
result = ""
Next, if the function is being used to decrypt text
, then it multiplies shift
par -1
to make it shift backward:
si decrypt:
shift = shift * -1
Finalement, caesar_cipher()
loops over the individual characters in text
and performs the following actions for each char
:
- Check if
char
is lowercase or uppercase. - Get the
index
duchar
in either thelowercase
ouuppercase
ASCII lists. - Add a
shift
to thisindex
to determine the index of the cipher character to use. - Utilisation
% 26
to make sure the shift will wrap back to the start of the alphabet. - Append the cipher character to the
result
string.
After the loop finishes iterating over the text
value, the result
is returned:
pour char dans text:
si char.islower():
index = lowercase.index(char)
result += lowercase[([([([(index + shift) % 26]
else:
index = uppercase.index(char)
result += uppercase[([([([(index + shift) % 26]
revenir result
Here’s the full code again:
import chaîne
def caesar_cipher(text, shift, decrypt=False):
si ne pas text.isascii() ou ne pas text.isalpha():
raise ValueError("Text must be ASCII and contain no numbers.")
lowercase = chaîne.ascii_lowercase
uppercase = chaîne.ascii_uppercase
result = ""
si decrypt:
shift = shift * -1
pour char dans text:
si char.islower():
index = lowercase.index(char)
result += lowercase[([([([(index + shift) % 26]
else:
index = uppercase.index(char)
result += uppercase[([([([(index + shift) % 26]
revenir result
Now run the code in the Python REPL using the text meetMeAtOurHideOutAtTwo
with a shift of dix
:
>>> caesar_cipher("meetMeAtOurHideOutAtTwo", dix)
woodWoKdYebRsnoYedKdDgy
The encrypted result is woodWoKdYebRsnoYedKdDgy
. Using this encrypted text, you can run the decryption to get the original text:
>>> caesar_cipher("woodWoKdYebRsnoYedKdDgy", dix, decrypt=True)
meetMeAtOurHideOutAtTwo
The Caesar cipher is fun to play around with for an introduction to cryptography. While the Caesar cipher is rarely used on its own, it’s the basis for more complex substitution ciphers. In the next section, you’ll look at one of the Caesar cipher’s descendants, the Vigenère cipher.
Vigenère Cipher
The Vigenère cipher is a polyalphabetic substitution cipher. To perform its encryption, it employs a different Caesar cipher for each letter of the input text. The Vigenère cipher uses a keyword to determine which Caesar cipher should be used to find the cipher letter.
You can see an example of the encryption process in the following image. In this example, the input text REALPYTHON
is encrypted using the keyword MODULO
:
For each letter of the input text, REALPYTHON
, a letter from the keyword MODULO
is used to determine which Caesar cipher column should be selected. If the keyword is shorter than the input text, as is the case with MODULO
, then the letters of the keyword are repeated until all letters of the input text have been encrypted.
Below is an implementation of the Vigenère cipher. As you’ll see, the modulo operator is used twice in the function:
import chaîne
def vigenere_cipher(text, key, decrypt=False):
si ne pas text.isascii() ou ne pas text.isalpha() ou ne pas text.isupper():
raise ValueError("Text must be uppercase ASCII without numbers.")
uppercase = chaîne.ascii_uppercase # "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
résultats = ""
pour je, char dans enumerate(text):
current_key = key[[[[je % len(key)]
char_index = uppercase.index(char)
key_index = uppercase.index(current_key)
si decrypt:
index = char_index - key_index + 26
else:
index = char_index + key_index
résultats += uppercase[[[[index % 26]
revenir résultats
You may have noticed that the signature for vigenere_cipher()
is quite similar to caesar_cipher()
from the previous section:
def vigenere_cipher(text, key, decrypt=False):
si ne pas text.isascii() ou ne pas text.isalpha() ou ne pas text.isupper():
raise ValueError("Text must be uppercase ASCII without numbers.")
uppercase = chaîne.ascii_uppercase
résultats = ""
The main difference is that, instead of a shift
parameter, vigenere_cipher()
takes a key
parameter, which is the keyword to be used during encryption and decryption. Another difference is the addition of text.isupper()
. Based on this implementation, vigenere_cipher()
can only accept input text that is all uppercase.
Comme caesar_cipher()
, vigenere_cipher()
iterates over each letter of the input text to encrypt or decrypt it:
pour je, char dans enumerate(text):
current_key = key[[[[je % len(key)]
In the above code, you can see the function’s first use of the modulo operator:
current_key = key[[[[je % len(key)]
Here, the current_key
value is determined based on an index returned from i % len(key)
. This index is used to select a letter from the key
string, such as M
de MODULO
.
The modulo operator allows you to use any length keyword regardless of the length of the text
to be encrypted. Once the index je
, the index of the character currently being encrypted, equals the length of the keyword, it will start over from the beginning of the keyword.
For each letter of the input text, several steps determine how to encrypt or decrypt it:
- Determine the
char_index
based on the index ofchar
insideuppercase
. - Determine the
key_index
based on the index ofcurrent_key
insideuppercase
. - Utilisation
char_index
etkey_index
to get the index for the encrypted or decrypted character.
Take a look at these steps in the code below:
char_index = uppercase.index(char)
key_index = uppercase.index(current_key)
si decrypt:
index = char_index - key_index + 26
else:
index = char_index + key_index
You can see that the indices for decryption and encryption are calculated differently. Voilà pourquoi decrypt
is used in this function. This way, you can use the function for both encryption and decryption.
After the index
is determined, you find the function’s second use of the modulo operator:
résultats += uppercase[[[[index % 26]
index % 26
ensures that the index
of the character doesn’t exceed 25
, thus making sure it stays inside the alphabet. With this index, the encrypted or decrypted character is selected from uppercase
and appended to résultats
.
Here’s the full code the Vigenère cipher again:
import chaîne
def vigenere_cipher(text, key, decrypt=False):
si ne pas text.isascii() ou ne pas text.isalpha() ou ne pas text.isupper():
raise ValueError("Text must be uppercase ASCII without numbers.")
uppercase = chaîne.ascii_uppercase # "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
résultats = ""
pour je, char dans enumerate(text):
current_key = key[[[[je % len(key)]
char_index = uppercase.index(char)
key_index = uppercase.index(current_key)
si decrypt:
index = char_index - key_index + 26
else:
index = char_index + key_index
résultats += uppercase[[[[index % 26]
revenir résultats
Now go ahead and run it in the Python REPL:
>>> vigenere_cipher(text="REALPYTHON", key="MODULO")
DSDFAMFVRH
>>> encrypted = vigenere_cipher(text="REALPYTHON", key="MODULO")
>>> impression(encrypted)
DSDFAMFVRH
>>> vigenere_cipher(encrypted, "MODULO", decrypt=True)
REALPYTHON
Agréable! You now have a working Vigenère cipher for encrypting text strings.
Python Modulo Operator Advanced Uses
In this final section, you’ll take your modulo operator knowledge to the next level by using it with decimal.Decimal
. You’ll also look at how you can add .__mod__()
to your custom classes so they can be used with the modulo operator.
Using the Python Modulo Operator With decimal.Decimal
Earlier in this tutorial, you saw how you can use the modulo operator with numeric types like int
et float
as well as with math.fmod()
. You can also use the modulo operator with Decimal
from the decimal
module. You use decimal.Decimal
when you want discrete control of the precision of floating-point arithmetic operations.
Here are some examples of using whole integers with decimal.Decimal
and the modulo operator:
>>> import decimal
>>> decimal.Decimal(15) % decimal.Decimal(4)
Decimal('3')
>>> decimal.Decimal(240) % decimal.Decimal(13)
Decimal('6')
Here are some floating-point numbers used with decimal.Decimal
and the modulo operator:
>>> decimal.Decimal("12.5") % decimal.Decimal("5.5")
Decimal('1.5')
>>> decimal.Decimal("13.3") % decimal.Decimal("1.1")
Decimal('0.1')
All modulo operations with decimal.Decimal
return the same results as other numeric types, except when one of the operands is negative. Unlike int
et float
, but like math.fmod()
, decimal.Decimal
uses the sign of the dividend for the results.
Take a look at the examples below comparing the results of using the modulo operator with standard int
et float
values and with decimal.Decimal
:
>>> -17 % 3
1 # Sign of the divisor
>>> decimal.Decimal(-17) % decimal.Decimal(3)
Decimal(-2) # Sign of the dividend
>>> 17 % -3
-1 # Sign of the divisor
>>> decimal.Decimal(17) % decimal.Decimal(-3)
Decimal("2") # Sign of dividend
>>> -13.3 % 1.1
1.0000000000000004 # Sign of the divisor
>>> decimal.Decimal("-13.3") % decimal.Decimal("1.1")
Decimal("-0.1") # Sign of the dividend
Compared with math.fmod()
, decimal.Decimal
will have the same sign, but the precision will be different:
>>> decimal.Decimal("-13.3") % decimal.Decimal("1.1")
Decimal("-0.1")
>>> math.fmod(-13.3, 1.1)
-0.09999999999999964
As you can see from the above examples, working with decimal.Decimal
and the modulo operator is similar to working with other numeric types. You just need to keep in mind how it determines the sign of the result when working with a negative operand.
In the next section, you’ll look at how you can override the modulo operator in your classes to customize its behavior.
Using the Python Modulo Operator With Custom Classes
The Python data model allows to you override the built-in methods in a Python object to customize its behavior. In this section, you’ll look at how to override .__mod__()
so that you can use the modulo operator with your own classes.
For this example, you’ll be working with a Étudiant
class. This class will track the amount of time a student has studied. Here’s the initial Étudiant
class:
class Étudiant:
def __init__(self, name):
self.name = name
self.study_sessions = []
def add_study_sessions(self, sessions):
self.study_sessions += sessions
le Étudiant
class is initialized with a name
parameter and starts with an empty list, study_sessions
, which will hold a list of integers representing minutes studied per session. There’s also .add_study_sessions()
, which takes a sessions
parameter that should be a list of study sessions to add to study_sessions
.
Now, if you remember from the converting units section above, convert_minutes_to_day()
used the Python modulo operator to convert total_mins
into days, hours, and minutes. You’ll now implement a modified version of that method to see how you can use your custom class with the modulo operator:
def total_study_time_in_hours(student, total_mins):
heures = total_mins // 60
minutes = total_mins % 60
impression(F"student.name studied heures hours and minutes minutes")
You can use this function with the Étudiant
class to display the total hours a Étudiant
has studied. Combined with the Étudiant
class above, the code will look like this:
class Étudiant:
def __init__(self, name):
self.name = name
self.study_sessions = []
def add_study_sessions(self, sessions):
self.study_sessions += sessions
def total_study_time_in_hours(student, total_mins):
heures = total_mins // 60
minutes = total_mins % 60
impression(F"student.name studied heures hours and minutes minutes")
If you load this module in the Python REPL, then you can use it like this:
>>> jane = Étudiant("Jane")
>>> jane.add_study_sessions([[[[120, 30, 56, 260, 130, 25, 75])
>>> total_mins = sum(jane.study_sessions)
>>> total_study_time_in_hours(jane, total_mins)
Jane studied 11 hours and 36 minutes
The above code prints out the total hours jane
studied. This version of the code works, but it requires the extra step of summing study_sessions
to get total_mins
before calling total_study_time_in_hours()
.
Here’s how you can modify the Étudiant
class to simplify the code:
class Étudiant:
def __init__(self, name):
self.name = name
self.study_sessions = []
def add_study_sessions(self, sessions):
self.study_sessions += sessions
def __mod__(self, autre):
revenir sum(self.study_sessions) % autre
def __floordiv__(self, autre):
revenir sum(self.study_sessions) // autre
By overriding .__mod__()
et .__floordiv__()
, you can use a Étudiant
instance with the modulo operator. Calculating the sum()
de study_sessions
is included in the Étudiant
class as well.
With these modifications, you can use a Étudiant
instance directly in total_study_time_in_hours()
. Comme total_mins
is no longer needed, you can remove it:
def total_study_time_in_hours(student):
heures = student // 60
minutes = student % 60
impression(F"student.name studied heures hours and minutes minutes")
Here’s the full code after modifications:
class Étudiant:
def __init__(self, name):
self.name = name
self.study_sessions = []
def add_study_sessions(self, sessions):
self.study_sessions += sessions
def __mod__(self, autre):
revenir sum(self.study_sessions) % autre
def __floordiv__(self, autre):
revenir sum(self.study_sessions) // autre
def total_study_time_in_hours(student):
heures = student // 60
minutes = student % 60
impression(F"student.name studied heures hours and minutes minutes")
Now, calling the code in the Python REPL, you can see it’s much more succinct:
>>> jane = Étudiant("Jane")
>>> jane.add_study_sessions([[[[120, 30, 56, 260, 130, 25, 75])
>>> total_study_time_in_hours(jane)
Jane studied 11 hours and 36 minutes
By overriding .__mod__()
, you allow your custom classes to behave more like Python’s built-in numeric types.
Conclusion
At first glance, the Python modulo operator may not grab your attention. Yet, as you’ve seen, there’s so much to this humble operator. From checking for even numbers to encrypting text with ciphers, you’ve seen many different uses for the modulo operator.
In this tutorial, you’ve learned how to:
- Use the modulo operator with
int
,float
,math.fmod()
,divmod()
, etdecimal.Decimal
- Calculate the results of a modulo operation
- Solve real-world problems using the modulo operator
- Override
.__mod__()
in your own classes to use them with the modulo operator
With the knowledge you’ve gained in this tutorial, you can now start using the modulo operator in your own code with great success. Happy Pythoning!
[ad_2]