Connexion élèves

Choisir le(s) module(s) à installer :

Fonctions - Applications

De nombreuses applications des notions Python que vous avec vues : variables, chaînes de caractères, conditions, boucles, fonctions.

Certaines applications sont à compléter, d'autres à écrire de A à Z !

Mais auparavant, lisez ce premier paragraphe qui met l'accent sur une notion fondamentale en programmation, à savoir documenter son code.

Documentation des fonctions

Vous venez d'écrire vos premières fonctions...pas de problème, vous savez parfaitement comment elles "fonctionnent", c'est à dire quel(s) paramètre(s) elles ont, et le type de résultat qu'elles renvoient...

Mais qu'en sera-t-il dans un mois ? voire même une semaine ?? Vous aurez ( sûrement ! ) oublié tout ça, et si vous devez réutiliser ou modifier une de ces fonctions, quelle perte de temps à se "remettre dedans" !

C'est pourquoi il est indispensable lorsqu'on écrit une fonction de la documenter, c'est à dire de fournir à l’utilisateur de cette fonction toutes les informations dont il a besoin pour l'utiliser.

Annotations de type

Les annotations de type sont des informations sur le type des paramètres et du résultat renvoyé par une fonction.

Considérons l'exemple ci-dessous :


def volume_sphere(r):
	volume = (4/3)*pi*r**3
	return volume
		

→ on sait que cette fonction prend un paramètre r de type flottant, et renvoie un résultat volume de type également flottant.
On peut alors préciser ces types dans l'en-tête de la fonction sous la forme :


def volume_sphere(r: float) -> float:
	volume = (4/3)*pi*r**3
	return volume
		

L'ensemble du nom d'une fonction, du nom et du type du (ou des) paramètre(s) qu'elle prend, ainsi que le type du ( ou des ) résultat(s) qu'elle renvoie est appelé la signature de la fonction.

Il est souvent très utile de disposer ainsi de la signature complète d'une fonction directement dans son en-tête de définition.

Voici les annotations de type que l'on peut utiliser ( certains types seront vus plus tard dans l'année ) :

  • int : nombre entier
  • float : nombre flottanr
  • str : chaîne de caractères
  • bool : booléen
  • list : tableau
  • dict : dictionnaire

Attention cependant, les annotations ne sont là qu’à titre indicatif. Rien n’empêche d'appeler la fonction volume_sphere() avec des chaînes de caractères, aucune erreur ne sera alors signalée du fait que le type du paramètre n'est pas le bon, mais le script a toutes les chances de ne pas fonctionner correctement ! 😎

Les annotations sont optionnelles; elles ne sont utiles que dans un but de documentation de la fonction ( c'est déjà bien ), pas pour vérifier son bon fonctionnement.

Les annotations de type sont une fonctionnalité relativement récente de Python ( version de Python >= 3.5 ) ; si vous rencontrez une erreur à leur sujet lors de l'écriture d'un script, ne les utilisez pas : votre version de Python est peut-être trop ancienne et ne les supporte pas.

Docstring d'une fonction

Il est d'usage de préciser toutes les informations nécessaires à l'utilisation de la fonction dans la docstring ( = "documentation string" ) de la fonction : il s'agit de commentaires placés au début de la définition de la fonction et qui constituent sa documentation.

Voici un exemple pour une fonction vue dans le cours :


def division(n1: int, n2: int ) -> int, int :  # deux résultats sont renvoyés, on annote donc leurs types à tous les deux
	"""
	Fonction pour calculer le quotient et le reste de la division de deux nombres.

	Entrée :
		deux nombres n1, n2
	Sortie :
		deux entiers dans l'ordre : quotient, reste de la division de n1 par n2
	"""

	quotient = n1 // n2
	reste = n1 % n2
	return quotient, reste
			

Ces commentaires sont placés entre deux groupes de triples guillemets ( """ ).

On précise ainsi quelles sont les spécifications en entrée et en sortie de la fonction, mais de plus, cette docstring est alors accessible depuis l'interpréteur Python grâce à la fonction help() ( ceci est d'ailleurs valable pour toute fonction ! ) :


>>> help(division)
Help on function division in module __main__:

division(n1 : int, n2 : int) -> int, int:
    Fonction pour calculer le quotient et le reste de la division de deux nombres.

    Entrée :
    	deux nombres n1, n2
    Sortie :
    	deux entiers dans l'ordre : quotient, reste de la division de n1 par n2

>>>
			

On remarque que la fonction help() affiche également les éventuelles annotations de type.

Dorénavant, à chaque fonction que vous écrirez, vous penserez impérativement à écrire une docstring succincte de votre fonction, et éventuellement, à indiquer les annotations de type dans son en-tête.

Comment !!

Minutes

  1. Compléter la fonction minutes() suivante pour qu'elle renvoie le nombre de minutes correspondant au nombre d'heures h et de minutes m passées en paramètres.
  2. Effectuer des appels de fonctions pour calculer et afficher le nombre de minutes correspondant à :
    • exemple 1 : 5 heures et 27 minutes
    • exemple 2 : 13 heures et 4 minutes
    • exemple 3 : 0 heure et 59 minutes
def minutes(heures: int, minutes: int) -> int: # Docstring à compléter pass

RÉPONSE

Œufs en boîte

On décide de ranger des œufs dans des boîtes de six.

  1. Programmer la fonction nb_boites() qui prend en paramètre un entier n correspondant à un nombre d’œufs et renvoie le nombre de boîtes nécessaires pour ranger les œufs.
  2. Vérifier que votre fonction satisfait le jeu de tests suivant :
    • nb_boites(8) == 2
    • nb_boites(3) == 1
    • nb_boites(6) == 1
    • nb_boites(38) == 7
    • nb_boites(600) == 100
    • nb_boites(601) == 101
    • nb_boites(0) == 0
  3. En utilisant votre fonction, déterminer combien de boîtes d'oeufs sont nécessaires pour ranger 45190 oeufs.
def nb_boites(oeufs: int) -> int: # Docstring à compléter pass

RÉPONSE

Nombre premier ( plusieurs return dans une même fonction )

On dit qu'un nombre entier positif est premier s'il admet exactement deux diviseurs (1 et lui même). Ainsi :

Mis à part pour 0 et 1 qui sont particuliers (et ne sont pas premiers), pour tester si un nombre n est premier il suffit de tester un par un tous les nombres compris entre 2 et n-1 : si l'un d'eux divise n, alors n n'est pas premier.

Par exemple pour tester si 323 est premier, il suffit de tester tous les nombres entre 2 et 322 : si l'un d'eux divise 323 alors 323 n'est pas premier ( en l'occurrence, on trouve que 17 divise 323, donc 323 n'est pas premier).

Remarque : Pour tester si n est divisible par k, on peut utiliser l'opérateur modulo % qui donne le reste dans la division euclidienne de n par k.

  1. Compléter la fonction est_premier() ci-dessous qui prend en paramètre un nombre n entier positif ou nul et renvoie un booléen indiquant si le nombre est premier (True) ou pas (False).
  2. Effectuer le jeu de tests suivants :
    • est_premier(0) == False
    • est_premier(1) == False
    • est_premier(4) == False
    • est_premier(6) == False
    • est_premier(48) == False
    • est_premier(57) == False
    • est_premier(77) == False
    • est_premier(2) == True
    • est_premier(3) == True
    • est_premier(5) == True
    • est_premier(7) == True
    • est_premier(11) == True
    • est_premier(13) == True
    • est_premier(89) == True
    • est_premier(241) == True
def est_premier(n: int) -> bool: """Fonction qui détermine si un nombre entier est premier ou pas. Entrée : n = le nombre à tester Sortie : un booléen True si le nombre est premier, False sinon """ if ... or ... : return False for i in ... : if ... : return False return True

RÉPONSE

Mot doublé

  1. Compléter le code de la fonction mot_double() ci-dessous pour qu'elle double chaque caractère de la chaîne ch passée en argument, quelle que soit sa longueur.
  2. Effectuer le jeu de tests suivants :
    • mot_double('MAC') == 'MMAACC'
    • mot_double('Z') == 'ZZ'
    • mot_double('Lovelace') == 'LLoovveellaaccee'
    • mot_double('Turing') == 'TTuurriinngg'
def mot_double(ch: str) -> str: # Doctring à écrire pass

Texte enrhumé

On dit qu'un texte est «enrhumé» lorsque certains caractères ont été remplacés par d'autres caractères correspondant à une prononciation «enrhumée».
Voici un exemple :

Quelle poisse d’être enrhume, une tisane s'il te plaît !
Guelle boizze d'êdre enrhube, une dizane z'il de plaid !

On utilise donc la table de correspondance ci-dessous :

Tableau de correspondance texte enrhumé
  1. Compléter la fonction enrhuber_chaine() suivante pour qu'elle renvoie la version "enrhumée" de la chaîne passée en argument.
  2. Effectuer le jeu de tests suivants :
    • enrhuber_chaine("place") == 'blage'
    • enrhuber_chaine("chant") == 'ghant'
    • enrhuber_chaine("arret") == 'arred'
    • enrhuber_chaine("ourse") == 'ourze'
    • enrhuber_chaine("stylo") == 'zdylo'
def enrhuber_chaine(chaine: str) -> str: pass

RÉPONSE

Le javanais

Le javanais ou langue de feu, apparu en France dans la dernière moitié du XIXe siècle, est un procédé de codage argotique [basé sur] l'insertion d'une syllabe supplémentaire entre voyelles et consonnes, dans le but de rendre ce texte moins compréhensible aux non initiés.
Cette syllabe comporte un son lié au nom de la variante : « ja » ou « av » dans la variante « javanaise » et une syllabe comportant « f » dans la variante « langue de feu ».( Source : Wikipedia )

Exemples :

Règles :

  1. Écrire une fonction javanais() qui prend en paramètre une chaîne de caractères, et renvoie la chaîne "traduite" en javanais
  2. tester la fonction avec les mots ci-dessus, voire avec une phrase complète ( les espaces entre les mots doivent être préservés ).
def javanais(chaine: str) -> str: pass

RÉPONSE

Réussir à l'examen

Dans tout ce qui suit les notes sont sur 20 points.

Voici un exemple de calcul de moyenne avec des coefficients :

Un examen comporte 6 épreuves :

Un·e étudiant·e peut être admis·e de deux façons :

  1. Programmer la fonction reussir_examen() qui prend les six notes des épreuves comme paramètres (fra, ang, phi, mat, phy et inf) et qui renvoie True ou False selon que l'étudiant·e est admis·e ou pas.
  2. Vérifier que votre fonction satisfait le jeu de tests suivant :
    • reussir_examen(10, 13, 11, 15, 6, 12) == True
    • reussir_examen(8, 13, 11, 15, 6, 12) == False
    • reussir_examen(10, 13, 11, 11, 6, 12) == False
    • reussir_examen(6, 3, 11, 15, 16, 20) == True
  3. En utilisant votre fonction déterminer si un·e étudiant·e ayant eu les notes suivantes (dans l'ordre des matières ci-dessus) : 8, 11, 14, 13, 9, 11 est admis·e ou pas.
def reussir_examen(fra: float, ang: float, phi: float, mat: float, phy: float, inf: float) -> bool: # Docstring à compléter pass

RÉPONSE

Casino

Dans un casino, les machines à sous comportent trois roues ou trois cylindres mécaniques portant chacun les chiffres de 1 à 9.
En faisant tourner ces roues ou cylindres, on peut tirer au hasard un nombre entre 111 et 999 (ne comportant pas de chiffre zéro).

Le joueur mise un euro et récupère un gain qui dépend du résultat :

  1. Compléter la fonction gain_tirage() qui prend en paramètre trois chiffres c, d et u correspondant aux chiffres des centaines, des dizaines et des unités et qui renvoie la somme récupérée correspondant à ce tirage.
  2. Vérifier que votre fonction satisfait le jeu de tests suivant :
    • gain_tirage(1, 7, 4) == 0
    • gain_tirage(4, 5, 6) == 15
    • gain_tirage(5, 7, 5) == 1
    • gain_tirage(4, 4, 4) == 33
    • gain_tirage(7, 7, 7) == 333
  3. En utilisant votre fonction, déterminer le gain associé au tirage (5, 6, 5).
  4. En utilisant la fonction gain_tirage(), compléter la fonction machine_a_sous() afin qu'elle renvoie trois chiffres tirés au hasard ainsi que la somme récupérée correspondante.
from random import randint def gain_tirage(c: int, d: int, u: int)->int: # instructions à compléter pass return somme def machine_a_sous()->int: # instructions à compléter pass return (c, d, u, somme)

RÉPONSE

Meilleur tarif

On considère les tarifs proposés par deux entreprises de location de véhicules pour la location d’un même modèle automobile :

  1. Programmer une fonction meilleur_tarif() qui :
    • prend en arguments : un entier km correspondant au nombre de kilomètres à parcourir, et un entier j correspondant au nombre de jours de location;
    • renvoie : l'entreprise qui propose le tarif le plus économique, ainsi que le tarif avec cette entreprise.
    On pourra consulter le jeu de tests si besoin.
  2. Vérifier que votre fonction satisfait le jeu de tests suivant :
    • meilleur_tarif(45, 1) == ('A', 27.15)
    • meilleur_tarif(75, 1) == ('A', 35.25)
    • meilleur_tarif(150, 1) == ('B', 54.5)
    • meilleur_tarif(150, 2) == ('A', 70.5)
    • meilleur_tarif(350, 2) == ('B', 118.5)
  3. En utilisant votre fonction, déterminer quel est le meilleur tarif pour parcourir 1250 kilomètres pendant 7 jours.
def meilleur_tarif(km: int, j: int) -> str, float: """Détermine l'entreprise proposant le meilleur tarif pour un nombre de km et de jour de location donnés. Entrées : km = le nombre de km parcourus jr = le nombre de jours de location Sortie : le nom de l'entreprise proposant le meilleur tarif la valeur de ce tarif """ pass

RÉPONSE

Super-Avare

Depuis ses huit ans, Super-avare économise des klipoks (monnaie locale).

  1. Compléter la fonction calculer_tirelire() qui prend en paramètre un entier n supérieur ou égal à 8 et renvoie le nombre entier correspondant au nombre de klipocks que Super-avare a dans sa tirelire le jour de son n-ième anniversaire.
  2. Effectuer le jeu de tests suivants :
    • calculer_tirelire(8) == 512
    • calculer_tirelire(9) == 1241
    • calculer_tirelire(10) == 2241
    • calculer_tirelire(11) == 3572
  3. Compléter la fonction age_millionnaire() qui utilise la fonction précédente pour renvoyer l'âge à partir duquel Super-avare devient millionnaire
def calculer_tirelire(n: int) -> int: # Docstring à compléter pass def age_millionnaire() -> int: # Docstring à compléter pass

RÉPONSE

Conversion binaire → base 10

Rappel de l'algorithme

	
on regarde successivement chaque bit du nombre binaire ( en commençant par le premier ou le dernier ) :

	si le bit courant est égal à 1 :
		alors on ajoute à la somme totale la puissance de 2 correspondant à la position du bit courant
	si le bit courant est égal à 0:
		on n'ajoute rien
			

Travail à faire

Écrire une fonction bin_vers_dec() qui :

  • prend comme paramètre une chaîne de caractère formée d'une succession de '0' et de '1' et représentant un nombre binaire.
  • renvoie son équivalent en base 10

Il faut coder l'algorithme que vous avez utilisé pour passer du binaire à la base 10.

Indication

Contrairement à ce que vous aviez ( peut-être ) fait lors des conversions "à la main", il est plus facile de coder cet algorithme en commençant par le bit de poids le plus grand ( le MSB ) : Python dispose en effet d'une fonction pour parcourir une chaîne de caractères depuis la gauche, cela peut servir ici...

Faites par contre bien attention au fait que, dans ce cas, on commence par la puissance de 2 la plus grande (27 pour un nombre à 8 bits par exemple ).

Cependant, les nombres binaires à convertir n'auront pas forcément 8 bits : il faut donc que la fonction s'adapte à un nombre quelconque n de bits.
Ce n'est pas très compliqué :

  • le nombre de bits n est le nombre de caractères qu'il y a dans la chaîne représentant le nombre binaire.
  • Souvenez-vous alors qu'avec n bits, on code 2n valeurs différentes : le MSB correspond donc toujours à la puissance 2n-1
def bin_vers_dec(binaire: str) -> int: """Convertit un nombre binaire en son équivalent décimal. Entrée : binaire = le nombre binaire Sortie : la conversion du nombre binaire en décimal """ n = ... dec = 0 for bit in ...: if bit == '1': dec = ... n = ... return dec

RÉPONSE

Conversion base 10 → binaire

Attention un peu plus délicat...

Contentez-vous pour ce script d'une conversion sur 8 bits ( donc des valeurs en base 10 comprises entre 0 et 255 ).

Rappel de l'algorithme


tant que le nombre en base 10 n'est pas nul:	
	
	on compare le nombre en base 10 à la plus grande puissance de 2 (2^7 pour un nombre sur 8 bits )
	si le nombre est supérieur ou égal à la puissance :
		alors on ajoute un bit '1' à la chaîne représentant le nombre binaire
		on soustrait la puissance au nombre en base 10
	sinon on ajoute un bit à '0' à la chaîne		
	
	on passe à  la puissance de 2 inférieure
			

Travail à faire

Écrire une fonction dec_vers_bin() qui:

  • prend comme paramètre un entier en base 10
  • renvoie une chaîne de caractères représentant la conversion de cet entier en binaire
def dec_vers_binaire(dec: int) -> str: """Fonction de conversion d'un nombre en base 10 vers le binaire. Entrée : dec = le nombre en base 10 Sortie : la conversion du nombre en base 10 vers le binaire """ binaire = "" puissance = 7 # conversion sur 8 bits ( peut être modifié ) while ... : if dec >= ... : binaire = ... dec = ... else: ... puissance = ... return binaire

RÉPONSE

Conversion base 10 → binaire ( bis )

Il existe un autre algorithme pour la conversion décimal → binaire :

Un autre algorithme


tant que quotient n'est pas nul :
	quotient ← division entière du nombre en base 10 par 2
	reste ← reste de la division entière du nombre en base 10 par 2 
	binaire ← "reste" + binaire
 	nombre en base 10 ← quotient

					

Travail à faire

Réarranger les instructions de la fonction dec_vers_bin_v2() ci-dessous qui utilise l'algorithme précédent; ne pas oublier l'indentation !

Vous pourrez vérifier le bon fonctionnement de votre solution dans l'éditeur ci-dessous :

RÉPONSE