Python - Les Fonctions, la modularité et les environnements virtuels
Chapitre 2 - Compréhension des fonctions et procédures en Python

Utiliser les procédures

Définition d'une procédure

Une procédure est un bloc d'instruction nommé et paramétré. Elle va réaliser certaines tâches. A chaque fois que la procédure est appelée, du code sera exécuté. Une procédure permet d'avoir ou non des paramètres.
Les procédures ont une particularité. Elles exécutent un bloc de code mais ne renvoient rien en fin d'exécution. C'est ce qui différencie la procédure de la fonction.

Le mot clé def

Le mot clé def permet de définir une procédure. Il faut lui donner un nom, des éventuels arguments entre parenthèse et finir avec le double point. Il ne faut pas oublier d'indenter la suite.

def presentation():
	print("Bonjour, je suis Jean-Philippe")
	print("J'ai 48 ans.")

En exécutant ce code, rien ne se passera. Pour que quelque chose ce produise dans la console, il faut appeler cette procédure.

def presentation():
	print("Bonjour, je suis Jean-Philippe")
	print("J'ai 48 ans.")

presentation()

Sortie console :
Bonjour, je suis Jean-Philippe
J'ai 48 ans.

Attention :
La procédure ce défini en début de code. La raison est que le code est exécuté de haut en bas. Si on appelle la procédure avant de l'avoir définie, une erreur NameError: Name 'presentation' is not defined sera affichée.

presentation()

def presentation():
	print("Bonjour, je suis Jean-Philippe")
	print("J'ai 48 ans.")

Sortie console :
presentation()
^^^^^^^^^^^^
NameError: name 'presentation' is not defined

Exploiter les paramètres de procédures

Présentation des arguments

Les paramètres de procédures sont aussi appelés les arguments. Dans les faits, il faut définir des variables en tant qu'arguments de la procédure. Comme cela, quand on appelle la procédure, on peut renseigner entre parenthèse le contenu de la variable.

def presentation(nom):
	print(f"Bonjour, je suis {nom}.")

presentation("Jean-Philippe")

Sortie console :
Bonjour, je suis Jean-Philippe.

L'avantage est qu'on peut appeler plusieurs fois la procédure tout en changeant le nom.

def presentation(nom):
	print(f"Bonjour, je suis {nom}.")

presentation("Jean-Philippe")
presentation("Luc")

Sortie console :
Bonjour, je suis Jean-Philippe.
Bonjour, je suis Luc.

Le nombre d'arguments n'est pas limité. Il faut penser que plus il y a d'arguments, plus cela devient complexes.

def presentation(nom, age):
	print(f"Bonjour, je suis {nom}.")
	print(f"J'ai {age} ans...")

presentation("Jean-Philippe", 48)
presentation("Luc", 23)

Sortie console :
Bonjour, je suis Jean-Philippe.
J'ai 48 ans...
Bonjour, je suis Luc.
J'ai 23 ans...

Arguments manquant lors de l'exécution

Si l'on oublie de renseigner un argument, une TypeError va apparaître.

def presentation(nom, age):
	print(f"Bonjour, je suis {nom}.")
	print(f"J'ai {age} ans...")

presentation()

Sortie console :
Traceback (most recent call last):
  File 
	 "..\02_Fonctions_Modularite_Env_virtuels
	    \C02_Comprehension_des_fonctions_et_procedures
	    \V02_Exploiter_les_parametres_de_procedures.py", line 12, in <module>
    presentation()
TypeError: presentation() missing 2 required positional arguments: 'nom' and 'age'

Arguments par défaut

Si l'on souhaite avoir des valeurs par défaut, c'est possible. Il faut ajouter un = avec la valeur souhaité après l'argument au moment de la définition.

Important :
Si un argument a une valeur par défaut, alors tous les arguments doivent en avoir une.

def presentation(nom="Jean-Philippe", age=48):
	print(f"Bonjour, je suis {nom}.")
	print(f"J'ai {age} ans...")

presentation()

Sortie console :
Bonjour, je suis Jean-Philippe.
J'ai 48 ans...

Le gros avantage est qu'il est possible de l'utiliser avec les valeurs par défaut mais également avec des valeurs saisie manuellement.

def presentation(nom="Jean-Philippe", age=48):
	print(f"Bonjour, je suis {nom}.")
	print(f"J'ai {age} ans...")

presentation()
presentation("Luc", 23)

Sortie console :
Bonjour, je suis Jean-Philippe.
J'ai 48 ans...
Bonjour, je suis Luc.
J'ai 23 ans...

Ordre des arguments

Il est possible de modifier l'ordre des arguments, pour autant qu'on ajoute leur nom en tant que paramètre. Cela fonctionnera aussi si les arguments n'ont pas de valeurs par défaut.

def presentation(nom="Jean-Philippe", age=48):
	print(f"Bonjour, je suis {nom}.")
	print(f"J'ai {age} ans...")

presentation(age = 33, nom = "Jean-Philippe")

Sortie console :
Bonjour, je suis Jean-Philippe.
J'ai 33 ans...

Autres exemples

def addition(nb1, nb2):
	print(f"La somme est de {nb1+nb2}")

addition(5,10)

Sortie console :
La somme est de 15

Les arguments arbitraires : args

les args se définissent avec une étoile. Mais dans la procédure, il ne faut pas la mettre. Le résultat sera un Tuple.

def addition(*args):
	print(args)

addition(1,2,3,11)

Sortie console :
(1, 2, 3, 11)

Pour pouvoir en tirer avantage, il faut utiliser une boucle for. Voilà l'explication de la procédure :

def addition(*args):
	total = 0 
	for arg in args:
		total += arg
	print(f"La somme est de {total}")

addition(1,2,3,11)

Sortie console :
La somme est de 17

Exemple 2

De convention, on utilise args. Mais on est pas obligé.

def presentation(*names):
	for name in names:
		print(f"Bonjour je suis {name}")

presentation("jean", "luc", "bob")

Sortie console :
Bonjour je suis jean
Bonjour je suis luc
Bonjour je suis bob

Utiliser les fonctions

Définition de la fonction

Une fonction est comme une procédure mais qui renvoie quelque chose.
Afin d'obtenir le résultat correct, il faut utiliser le mot clé return.

Dans le cas de l'exemple suivant, la console reste vide. La raison est que la fonction a renvoyé une valeur mais elle n'a pas été stockée.

def ma_fonction():
	return "ceci est la valeur de ma fonction"

ma_fonction()

Pour obtenir le résultat escompté, il faut injecter la fonction dans une variable.

def ma_fonction():
	return "ceci est la valeur de ma fonction"

val = ma_fonction()
print(val)

Sortie console :
ceci est la valeur de ma fonction

Important :
La grosse différence avec la procédure, c'est que la fonction reçoit une valeur, une information.

Retour de plusieurs valeurs

Il est possible de retourner plusieurs valeurs. Cela va renvoyer un tuple. Afin de l'exploiter correctement, il faut stocker le tuple dans des variables distinctes.

def ma_fonction():
	return "Jean-Philippe", 47

nom , age = ma_fonction()

print("mon nom est", nom)
print("J'ai", age, "ans")

Sortie console :
mon nom est Jean-Philippe
J'ai 47 ans

Valeur par défaut d'une fonction avec return vide

Par défaut, le return d'une fonction fonction va renvoyer None. C'est pourquoi il ne faut pas oublier de completer le return.

def ma_fonction():
	return

print(ma_fonction())

Sortie console :
None

Exploiter les paramètres d'une fonction

Paramètres et valeurs par défaut des fonctions

Tout comme pour les procédures, il est possible de définir des arguments pour les fonctions. Il est également possible de définir des valeurs par défaut pour ces arguments.

Sans valeur par défaut :
def addition(nb1, nb2):
	return nb1+nb2

somme = addition(10,2)

print(somme)

Sortie console :
12
Avec valeur par défaut :
def addition(nb1 = 1, nb2 = 1):
	return nb1+nb2

somme = addition()

print(somme)

Sortie console :
2
soustraction avec valeur par défaut :
def soustraction(nb1 = 1, nb2 = 1):
	return nb1 - nb2

result = soustraction()

print(result)

Sortie console :
0
Soustraction avec variable inversée :
def soustraction(nb1 = 1, nb2 = 1):
	return nb1 - nb2
			
result = soustraction(nb2 = 10, nb1 = 2)

print(result)

Sortie console :
-8

Arguments arbitraires pour les fonctions

Comme pour les procédures, il est possible d'utiliser les arguments arbitraires dans les fonctions.

Soustraction avec args :
def soustraction(*nums):
	total = 0
	for n in nums:
		total -= n
	return total

print(soustraction(1,1,1))

Fonction dans une fonction

Il est possible de faire appelle à une fonction dans une fonction pour autant qu'elle ait été déclarée avant.

def addition(nb1, nb2):
	return nb1 + nb2

def affiche(n1, n2):
	nombre = addition(n1, n2)
	print("addition est ", nombre)

print(affiche(10, 10))

Sortie console :
addition est 20
None (Chez Alphorm, le none n'apparaît pas. Pourquoi ?)

Les kwargs

En utilisant *args, l'étoile va générer un Tuple.
En utilisant **kwargs, les deux étoiles vont générer un dictionnaire.

Astuce :
Tout comme pour args, kwargs est utilisé de convention.

Si l'on utilise que les kwargs comme on le faisait avec les args dans une procédure, une erreur va apparaître.

def total_vente(**kwargs):
	print(kwargs)

total_vente(1,2,3)

Sortie console :
TypeError: total_vente() takes 0 positional arguments but 3 were given

En appelant la procédure avec des données renseignées sous forme de dictionnaire, on obtient le bon résultat.
Les accolades dans la console montre bien que c'est un dictionnaire.

def total_vente(**kwargs):
	print(kwargs)

total_vente(Jean=2, Luc=4, Zoe=8)

Sortie console :
{'Jean': 2, 'Luc': 4, 'Zoe': 8}

En adaptant la procédure pour obtenir une fonction, on peut bien obtenir le résultat des ventes.

def total_vente(**kwargs):
	total = 0
	for v in kwargs.values():
		total += v
	return total

print(total_vente(Jean=2, Luc=4, Zoe=8))

Sortie console :
14

Utiliser les fonctions lambda

Définition de la fonction lambda

La fonction lambdaest une petit fonction contenant une seule expression. Elle peut aussi agir sous anonymat parce qu'elle ne nécessite aucun nom. C'est pour cela qu'elle est également appelée fonction anonyme.
Une fonction lambda ne peut avoir qu'une seule expression mais plusieurs arguments.

Créer la fonction lambda

Pour créer la fonction lambda, il nous faut ceci :
lambda <arguments> : <Expression>

Pour éviter une erreur de fonction dans la console, il faut directement la stocker dans une variable. Donc :
variable = lambda <arguments> : <Expression>

Il y a deux cas où la fonction lambda peut-être utile.

Effectuer des petites tâches avec moins de code

Si l'on cherche à faire une fonction pour trouver le carré d'un nombre ou une addition de 4 nombres, on pourrait avoir ceci :

Carré d'un nombre :
def carre(x):
	return x * x

print(carre(2))

Sortie console :
4
Addition de 4 nombres :
def some(w,x,y,z):
	return w + x + y + z

	print(some(1,1,1,1))

Sortie console :
4

Voilà 2 les fonctions lambda qui correspondent aux exemple ci-dessus :

Carré d'un nombre :
carre = lambda x : x * x
print(carre(2))

Sortie console :
4
Addition de 4 nombres :
somme = lambda w, x, y, z : w + x + y + z
print(somme(1,1,1,1))

Sortie console :
4

Il est également possible d'utiliser des valeurs par défaut pour les arguments.

Valeur par défaut :
somme = lambda w=0, x=0, y=0, z=0 : w + x + y + z
print(somme(1,1))

Sortie console :
2

La fonction map

La fonction map renvoie un élément de classe objet. Elle permet de faire appelle à une autre fonction avec un nombre d'itération défini.
Si on stock le résultat dans une variable, cela va générer une erreur mémoire :

def	addition(n):
	return n + n

nombres = [1,2,3,4]

resultat = map(addition,nombres)

print(resultat)

Sortie console :
<map object at 0x0000021A06C29E70>

Si l'on veut récupérer le résultat correctement, il faut caster la variable lors de la sortie :

def	addition(n):
	return n + n

nombres = [1,2,3,4]

resultat = map(addition,nombres)

print(resultat)

Sortie console :
[2, 4, 6, 8]

La fonction lambda appelle d'autres fonctions

Le 2ème cas de figure pour utiliser la fonction lambda est pour appeler d'autres fonctions.

nombres = [1,2,3,4]
resultat = map(lambda x : x + x, nombres)

print(list(resultat))

Sortie console :
[2, 4, 6, 8]

Comment obtenir de l'aide sur une fonction

Pour commencer, dans la console, il faut taper py + ENTER.
Cela va lancer l'interpréteur dans la console.

Ensuite, il suffit de tapper help + ESPACE + (nom-de-la-fonction).
help (map)

Astuce :
Si -- Suite -- apparaît dans la console, alors il faut appuyer sur ENTER pour que la suite apparaisse dans la console.
Pour sortir de l'interpréteur Python et revenir dans la simple console, il faut taper CTRL + Z ENTER.

Comprendre la portée locale et globale

Il faut distinguer la portée local de la portée globale. La portée local aura un impact uniquement dans une fonction par exemple. Si on crée une variable dans une fonction est qu'on cherche à l'appeler en dehors, alors on aura une erreur NameError.
Cela vaut dans tous les types de blocs de code (if, while, try, etc.), pas uniquement dans les fonctions.

def somme(nb1, nb2):
	result = nb1 + nb2
	return result

print(somme(2,4))
print(result)

Sortie console :
6
print(result)
NameError: name 'result' is not defined

Si on déclare la variable avant la fonction, elle aura toujours une portée locale à l'intérieur du fichier dans lequel elle a été crée. Elle pourra donc être utilisée dans la fonction dans ce même fichier (pour autant que la fonction soit définie après la variable).

Exemple 1: On utilise le même nom de variable à l'extérieur et à l'intérieur de la fonction.
result = 0

def somme(nb1, nb2):
	print(result)
	result = nb1 + nb2
	return result

print(somme(2,4))
print(result)

Sortie console :
print(somme(2,4))
print(result)
UnboundLocalError: cannot access local variable 'result' where it is not associated with a value
Exemple 2 : On utilise des noms de variables différents.
result = 0
var = 11

def somme(nb1, nb2):
	print(var)
	result = nb1 + nb2
	return result

print(somme(2,4))
print(result)

Sortie console :
11 (cela vient de var)
6 (cela vient du print(somme))
0 (cela vient de result en dehors de la fonction)

Définir une variable à portée globale

Afin de pouvoir accéder en dehors d'une fonction à une variable, il faut la définir en tant que variable locale. Pour ce faire, il suffit de noter le mot clé globale puis le nom de la variable.

Important :
Il ne faut définir la valeur de la variable, uniquement définir qu'elle est globale.

def somme(nb1, nb2):
	global result
	result = nb1 + nb2
	return result

print(somme(2,4))
print(result)

Sortie console :
6
6

Une fois que la portée globale a été définie sur une variable, on peut la réutiliser à l'extérieur du bloc de code sans soucis.

def somme(nb1, nb2):
	global result
	result = nb1 + nb2
	return result

print(somme(2,4))
print(result)

result +=1
print(result)
Sortie console 
6 6 7

Comprendre les fonctions locales et globales

Exercice pratique : Réaliser une fonction qui renvoie le nombre de voyelles

Correction de l'exercice pratique.