TP3 Fonctions

Transcription

TP3 Fonctions
IGI-3008 – ESIEE Paris – 2016-2017
Apprentissage de la Programmation avec Python
TP3
Jean-Claude GEORGES
Ce TP est consacré aux fonctions et méthodes, à leurs définitions et leurs utilisations.
Après une présentation de quelques éléments de syntaxe, vous pourrez commencer à
écrire vos propres fonctions.
Les fonctions et méthodes
Une fonction est un traitement, nommé ou anonyme, permettant d’opérer sur zéro ou
plusieurs données (les arguments de la fonction) et de calculer éventuellement un résultat.
Une méthode est un traitement nommé s’appliquant à un objet ou à une classe ayant
défini la méthode permettant d’opérer sur cet objet ou cette classe, sur zéro ou plusieurs
autres données et de calculer éventuellement un résultat.
L’utilisation d’une fonction se fait par l’invocation de son nom, suivi d’une séquence
d’arguments (éventuellement vide) entre parenthèses, séparées par des virgules.
L’utilisation d’une méthode se fait par l’invocation de l’objet (ou la classe) sur lequel elle
s’applique, suivie d’un poit, puis du nom de la méthode, et d’une séquence d’arguments
entre parenthèses, séparés par des virgules.
Pour programmer et pouvoir utiliser ses propres fonctions, il faut les définir.
La syntaxe est la suivante :
def nomfonction (séquenceDesParamètres):
corps de la fonction indenté par rapport à sa 1ère ligne
avec éventuellement une ligne return expression
Les paramètres sont des noms, séparés par des virgules. Lors de l’appel, tout se passe
comme si, avant la première instruction de la fonction, des affectations se faisaientt avec
à gauche les noms des paramètres et à droite les valeur des arguments d’appel de même
rang. L’instruction return (ou la fin du corps de la fonction) interrompt son exécution et
retourne l’expression au traitement appelant (ou la valeur None s’il n’y a pas de return)
Figure 1 — Exemple d’utilisation d’une fonction
La fonction pow permet de calculer x y de cette façon :
>>> pow(2, 15)
32768
Figure 2 — Exemple d’utilisation d’une méthode
La méthode find de la classe str permet de trouver l’emplacement
d’une sous-chaîne dans une chaîne :
>>> "abracadabra".find('dab')
6
Figure 3 — Définition et utilisation d’une fonction
>>> def f(a, b, c):
...
print(a, b, c)
...
>>> x, y, z = 1, 10, 100
>>> f(x, x + y, x * y * z)
1 11 1000
>>> # tout se passe comme si
>>> # on copiait/collait le corps de la fonction
>>> # ici la ligne print(a, b, c)
>>> # précédé de l'affectation a, b, c = x, x + y, x * y * z
DÉFINITION DE FONCTION
2
Définition de fonction
Figure 4 — Afficher ou retourner ?
def aff_carré(x):
print(x ** 2)
Exercice 1 — print() ou return ?
def carré(x):
return x ** 2
Saisissez les deux fonctions de la figure 4.
La différence ne se voit pas lorsque l’on invoque les fonctions dans un shell : invoquez
>>> aff_carré(7)
puis
>>> carré(7)
Mais si vous utilisez ces fonctions dans une expression, la différence saute aux yeux !
%>>> aff_carré(7)+1
puis
>>> carré(7)+1
Expliquez cette différence.
Figure 5 — Définition de la factorielle
n! = 1 × 2 × ... × (n − 1) × n
Figure 6 — Les 169 chiffres de 105!
Exercice 2 — Factorielle (1)
105! =
Écrivez la fonction factorielle1(n) qui calcule à l’aide d’une boucle (itérativement) la
factorielle de n.
TP3
IGI-3008 (2016-2017)
1
081
39675
8240290
900504101
30580032964
9720646107774
902579144176636
57322653190990515
3326984536526808240
339776398934872029657
99387290781343681609728
0000000000000000000000000
DÉFINITION DE FONCTION
3
Figure 7 — La première version de ppfp
Exercice 3 — Le plus petit diviseur
Le but de cet exercice est d’écrire une fonction ppfp(n) qui retourne le plus petit diviseur
du nombre entier n (on suppossera n ≥ 2)
• première version : entrez une première version ppfp01(n) (voir figure 7) basée sur le
principe suivant : on essaie de diviser n par tous les nombres de 2 à n − 1. Si une
division tombe juste, on retourne le diviseur ; si aucune division ne tombe juste, on
retourne n car le nombre est premier.
def ppfp01(n):
d = 2
while d < n: # de 2 à n-1
if n % d == 0: # si une division tombe juste
return d
else:
d += 1
else: # si tous ont été testés
return n
Note : il est toujours utile d’écrire une version non optimisée et de la garder afin de
disposer d’une version qui tourne et permettant de tester les futures versions.
• deuxième version : écrivez ppfp02(n) sur le principe suivant : on essaie de diviser n
√
par tous les nombres de 2 à n (while d*d <= n:). Si une division tombe juste, on
retourne le diviseur ; si aucune division ne tombe juste, on retourne n (le nombre est
premier). Testez ce programme avec 2, 3, 4, 23, 25, 27, 1 000 003, 10 000 019. Comparez
les temps d’exécution entre les deux versions pour 1 000 003 et 10 000 019.
• troisième version : écrivez ppfp03(n) qui traite le cas n pair à part. Si n est impair, on
essaiera les diviseurs à partir de 3 et de 2 en 2. Comparez les temps d’exécution entre
les trois versions pour 1 000 003 et 10 000 019.
La fonction ci-contre (Fig. 9) calcule la chaîne de caractères correspondant à l’écriture du
nombre entier n en base b. Modifiez-la pour qu’elle gère les nombres négatifs.
Modifiez-la pour qu’un appel avec le seul paramètre n donne la chaîne de caractères
correspondant à l’écriture du nombre n en base 10 (valeur de b par défaut).
IGI-3008 (2016-2017)
√
n?
Si nous√n’avons trouvé aucun diviseur qui soit inférieur ou
égal à n, il n’est pas nécessaire de poursuivre les essais
√
au delà. En effet, s’il existait un diviseur supérieur √
à n,
le quotient de n et de ce diviseur serait inférieur à n et
nous l’aurions vu.
√
d >
n
1
1
< √
d
n
n
n
< √
d
n
√
n
<
n
d
Figure 9 — Conversion en base
Exercice 4 — Conversion en base b
TP3
Figure 8 — Pourquoi peut-on s’arrêter à
def convert_base(n, b):
a = '0123456789ABCDEF'
s = ''
while True:
s = a[n % b] + s
n //= b
if n == 0:
break
return s
ARGUMENTS NOMMÉS
4
Arguments nommés
Python transmet les arguments lors d’un appel de fonctions dans l’ordre de la déclaration.
Toutefois, on peut court-circuiter l’ordre des arguments en les nommant, à condition qu’il
n’y ait pas d’ambiguïté.
Exercice 5 — Appels de fonctions avec mots clefs
Soient la définition de fonction suivante :
def f(x, y=2, z=3) :
print("x=", x, "
y=", y, "
z=", z, sep='')
Exécutez-la avec les invocations suivantes. Certaines s’exécutent sans erreurs et d’autres
ne peuvent pas s’exécuter. Comprenez les messages d’erreurs.
>>> f(1)
>>> f(1, 3, 4)
>>> f()
>>> f(z=1000, x=10, y=100)
>>> f(10, y=100, 1000)
>>> f(10, z=1000, y=100)
>>> f(z=1000, x=10)
>>> f(10, x=1000)
>>> f(10, y=1000)
>>> f(10, z=1000)
TP3
IGI-3008 (2016-2017)
RÉCURSIVITÉ
5
Figure 10 — Le jeu du + ou #
#
#
#
#
Exercice 6 — Le jeu du plus ou moins
Transformez le programme de l’exercice Le jeu du + ou - du TP1 (cf. Fig. 10) en une
fonction dont les paramètres sont les bornes de l’intervalle dans lequel se trouve le nombre
à deviner, et valent par défaut 0 et 999.
Récursivité
Une fonction récursive est une fonction qui s’appelle elle-même (directement ou indirectement)
dans sa définition.
Le corps d’une fonction récursive comporte toujours dans une alternative un cas
particulier (que l’on sait traiter directement) et un cas général que l’on sait traiter indirectement
en utilisant un appel à la fonction avec des arguments se rapprochant du cas particulier.
Exercice 7 — Factorielle (2)
Écrivez la fonction factorielle2(n) qui calcule récursivement la factorielle de n
(définition récursve en fig 12).
fichier : devine2.py
auteur : Jean-Claude GEORGES
date : 21/06/2013
màj : 06/09/2016
exemple simple de programme python : le nombre à deviner
import random # pour générer des nombres pseudo-aléatoires
########## introduction ##################
print (""" Voici le classique jeu du nombre à deviner (niveau Adibou).
L'ordinateur va choisir un nombre au pseudo-hasard
et tu vas essayer de le deviner .""")
######## initialisation ##################
MINI, MAXI = 1, 999 # double affectation pour les bornes du jeu
NB_MAX_ESSAIS = 3
nb_essais = 0 # nombre d'essais
trouvé = False # type booleen
nb_à_deviner = random.randrange(MINI, MAXI +1) # nombre à deviner
msg = 'Propose un nombre entre ' + str(MINI) + ' et ' + str(MAXI)+ ' : '
########## corps du programme ##################
while not trouvé and nb_essais < NB_MAX_ESSAIS: # tant qu'on n'a pas trouvé
x = input(msg) # saisie
if x=='aparecium': # cheat code : révèle une éventuelle écriture invisible
print(nb_à_deviner)
continue
x = int(x) # int convertit un texte en entier
nb_essais += 1
if x < nb_à_deviner:
print ("
C'est plus ! Essaie encore !")
elif nb_à_deviner < x:
print ("
C'est moins ! Essaie encore !")
else: # x == nb_à_deviner
trouvé = True
########## fin du programme ####################
if trouvé:
print ("\nBravo. Tu as deviné le nombre en ",
nb_essais, " tentative",
's' if nb_essais > 1 else '', sep = '', end = ' ! ')
else:
print("\nPerdu. Nombre maximal d'essais atteint")
print("\n"*5,"Merci d'avoir joué...")
Figure 11 — Exemple de fonction récursive : le pgcd
Définitions
mathématique récursive
pgcd( a, 0) = a
pgcd( a, b) = pgcd(b, a mod b)
Programme python correspondant
def pgcd(a, b):
if b == 0: # cas particulier
return a
else: # cas général
return pgcd(b, a % b)
# a %b < b nous raproche de b==0
Figure 12 — Définition récursive de la factorielle
0! = 1
n! = n × (n − 1)!
TP3
IGI-3008 (2016-2017)
RANGES ET GÉNÉRATEURS
6
Ranges et générateurs
Un range est un générateur d’éléments de suites arithmétiques. Sa syntaxe est :
range(start, stop, step).
Les nombres générés suivent la formule ui = start + step × i avec i ≥ 0. La génération
s’arrête dès que ui ≥ stop si step > 0 (par défaut il vaut 1) ou dès que ui ≤ stop si step < 0.
Figure 13 — Affichage d’un range
# affichage des multiples de 3 entre 3 et 30
for i in range(3,31,3):
print(i, end = ' ')
Exercice 8 — Les suites entières
Sur l’exemple de la figure 13, écrivez les programmes suivants :
• affichage des nombres entiers de 0 à 20 (inclus)
• affichage du compte à rebours de 10 à 0 (inclus)
• affichage des nombres entiers de −80 à 80 (inclus) par pas de 10
• affichage des multiples de 7 de 80 à 153 (inclus)
• affichage des multiples de m de a à b (inclus)
Un générateur est un traitement nommé permettant d’opérer sur 0 ou plusieurs données
et de calculer une suite de résultats accessibles successivement à l’aide d’une boucle for
ou de l’invocation de la fonction next sur ce générateur.
Un générateur s’écrit comme une fonction, mais avec une ligne yield expression au lieu
d’une ligne return expression. Lors de l’invocation du générateur dans une boucle for
par exemple, il s’exécute jusqu’à rencontrer un yield, suspend son exécution et retourne
l’expression. Lors des tours de boucles suivants, l’exécution reprendra à la ligne suivant le
yield, toutes les données étant mémorisées (voir l’exemple Fig. 14).
TP3
IGI-3008 (2016-2017)
Figure 14 — Le générateur des lettres d’une chaîne
def gencar(s):
for x in s:
if x.isalpha(): # si x est une lettre
yield x
for x in gencar("R2D2 a rencontré 12 aliens !"):
print(x, end = '')
RDarencontréaliens
RANGES ET GÉNÉRATEURS
7
Figure 15 — Une curiosité : les nombres univers
Un nombre est dit nombre univers si son écriture en base 10 contient
tout nombre entier fini. Le nombre formé de la mise bout à bout
de toutes les puissances de 2 est un nombre univers : tout entier
apparaît dans au moins une puissance de 2.
Par exemple, les 3 premiers chiffres significatifs de π (314)
apparaissent dans 274 (= 188894659 314 78580854784).
Le film que vous avez regardé sur votre ordinateur hier soir (en
format .avi) est un énorme nombre. Il est donc présent dans une
puissance de 2.
Exercice 9 — Puissances de 2 et nombres univers
def genpuiss2():
p = 1
while True: #générateur infini
yield p
p *= 2
#exemple d'utilisation
#affichage des puissances de 2 de 1 à 1000000
for i in genpuiss2():
if i>1000000:
break # utilisation finie du générateur infini
print(i, end=' ')
Utilisez le générateur ci-dessus pour vérifier que votre date de naissance (sous la forme
d’une chaîne de caractère "010194") apparaît dans une puissance de 2. Laquelle ? (on
pourra utiliser str(n) pour convertir un nombre n en la chaîne de caractères le représentant
et s1 in s2 pour savoir si la chaîne s1 est présente dans la chaîne s2)
Essayez d’afficher l’exposant de 2 dont la puissance contient votre date de naissance (par
exemple, la date 19/09/16 sous la forme "190916" est contenue dans les chiffres de 23615 ).
Essayez de présenter la puissance de 2 qui contient votre date de naissance en mettant
en valeur cette date (comme dans la figure 15 ).
Note : la coutume veut que la personne ayant la plus petite puissance de 2 contenant sa date de naissance offre le restaurant à l’ensemble du groupe.
TP3
IGI-3008 (2016-2017)

Documents pareils