Lesson 5/9 7 min

Functions

Create reusable blocks with def, parameters, return, *args, **kwargs and built-in functions.

FR EN

def : créer une fonction

Une fonction est un bloc de code réutilisable. On la définit avec def :

def saluer(nom):
    print(f"Bonjour {nom} !")

saluer("Alice")  # Bonjour Alice !
saluer("Bob")    # Bonjour Bob !

Le mot-clé return permet à la fonction de renvoyer une valeur :

def additionner(a, b):
    return a + b

resultat = additionner(3, 5)
print(resultat)  # 8

Rappel : l'indentation (4 espaces) définit le corps de la fonction. Tout ce qui est indenté après def fait partie de la fonction.

Paramètres par défaut

On peut donner une valeur par défaut à un paramètre :

def saluer(nom, langue="fr"):
    if langue == "fr":
        print(f"Bonjour {nom} !")
    else:
        print(f"Hello {nom}!")

saluer("Alice")           # Bonjour Alice !
saluer("Bob", "en")       # Hello Bob!
saluer("Charlie", langue="en")  # Hello Charlie!

Les paramètres avec défaut doivent être après les paramètres obligatoires.

*args et **kwargs : paramètres flexibles

*args accepte un nombre variable d'arguments :

def moyenne(*notes):
    return sum(notes) / len(notes)

print(moyenne(15, 12, 18))      # 15.0
print(moyenne(10, 20, 14, 16))  # 15.0

**kwargs accepte des arguments nommés (comme un dictionnaire) :

def creer_profil(**infos):
    for cle, valeur in infos.items():
        print(f"{cle}: {valeur}")

creer_profil(nom="Alice", age=25, ville="Paris")

Résultat :

nom: Alice
age: 25
ville: Paris

Fonctions lambda

Une lambda est une fonction anonyme en une ligne :

# Fonction classique
def doubler(x):
    return x * 2

# Même chose en lambda
doubler = lambda x: x * 2
print(doubler(5))  # 10

# Utile pour le tri
utilisateurs = [("Alice", 25), ("Bob", 30), ("Charlie", 20)]
utilisateurs.sort(key=lambda u: u[1])
print(utilisateurs)
# [('Charlie', 20), ('Alice', 25), ('Bob', 30)]

Fonctions built-in utiles

Python fournit des dizaines de fonctions prêtes à l'emploi :

# len, range, enumerate
fruits = ["pomme", "banane", "cerise"]
print(len(fruits))  # 3

for i, fruit in enumerate(fruits):
    print(f"{i}: {fruit}")
# 0: pomme
# 1: banane
# 2: cerise

# zip : combiner des listes
noms = ["Alice", "Bob"]
ages = [25, 30]
for nom, age in zip(noms, ages):
    print(f"{nom} a {age} ans")
# Alice a 25 ans
# Bob a 30 ans

# map et filter
nombres = [1, 2, 3, 4, 5]
doubles = list(map(lambda x: x * 2, nombres))
pairs = list(filter(lambda x: x % 2 == 0, nombres))
print(doubles)  # [2, 4, 6, 8, 10]
print(pairs)    # [2, 4]

Annoter les types : les type hints

Vous l'avez vu dans l'introduction : Python est dynamiquement typé, vous n'êtes jamais obligé de préciser le type d'une variable. Mais depuis Python 3.5, vous pouvez annoter vos variables et vos fonctions pour indiquer le type que vous attendez. On appelle ça les type hints.

def addition(a: int, b: int) -> int:
    return a + b

print(addition(2, 3))   # 5

# On peut aussi annoter une variable
age: int = 25
nom: str = "Alice"
print(f"{nom} a {age} ans")

La syntaxe est simple : a: int pour un paramètre, et -> int après les parenthèses pour annoncer le type de retour.

Note : ces annotations ne sont pas vérifiées à l'exécution. Python les ignore complètement quand il fait tourner le code : si vous passez un mauvais type, ça marche quand même (ou ça plante plus loin). Une annotation est une indication, pas une garantie.

def addition(a: int, b: int) -> int:
    return a + b

# Python ne bronche pas, meme avec des chaines :
print(addition("a", "b"))   # ab

Bonne pratique : annotez vos fonctions dans les vrais projets. Les type hints ne changent rien à l'exécution, mais ils rendent le code plus lisible, permettent à votre éditeur de proposer l'autocomplétion et de repérer des erreurs, et un outil comme mypy peut vérifier tout le code avant qu'il tourne. C'est l'équivalent Python du typage vu en JavaScript et en PHP.

def — creating a function

A function is a reusable block of code. Define one with def:

def greet(name):
    print(f"Hello {name}!")

greet("Alice")  # Hello Alice!
greet("Bob")    # Hello Bob!

The return keyword lets the function send back a value:

def add(a, b):
    return a + b

result = add(3, 5)
print(result)  # 8

Reminder: indentation (4 spaces) defines the function body. Everything indented after def is part of the function.

Default parameters

You can give a parameter a default value:

def greet(name, language="en"):
    if language == "en":
        print(f"Hello {name}!")
    else:
        print(f"Bonjour {name} !")

greet("Alice")             # Hello Alice!
greet("Bob", "fr")         # Bonjour Bob !
greet("Charlie", language="fr")  # Bonjour Charlie !

Parameters with defaults must come after required parameters.

*args and **kwargs — flexible parameters

*args accepts a variable number of arguments:

def average(*grades):
    return sum(grades) / len(grades)

print(average(15, 12, 18))      # 15.0
print(average(10, 20, 14, 16))  # 15.0

**kwargs accepts named arguments (like a dictionary):

def create_profile(**info):
    for key, value in info.items():
        print(f"{key}: {value}")

create_profile(name="Alice", age=25, city="Paris")

Result:

name: Alice
age: 25
city: Paris

Lambda functions

A lambda is an anonymous one-line function:

# Regular function
def double(x):
    return x * 2

# Same thing as lambda
double = lambda x: x * 2
print(double(5))  # 10

# Useful for sorting
users = [("Alice", 25), ("Bob", 30), ("Charlie", 20)]
users.sort(key=lambda u: u[1])
print(users)
# [('Charlie', 20), ('Alice', 25), ('Bob', 30)]

Useful built-in functions

Python provides dozens of ready-to-use functions:

# len, range, enumerate
fruits = ["apple", "banana", "cherry"]
print(len(fruits))  # 3

for i, fruit in enumerate(fruits):
    print(f"{i}: {fruit}")
# 0: apple
# 1: banana
# 2: cherry

# zip — combine lists
names = ["Alice", "Bob"]
ages = [25, 30]
for name, age in zip(names, ages):
    print(f"{name} is {age} years old")
# Alice is 25 years old
# Bob is 30 years old

# map and filter
numbers = [1, 2, 3, 4, 5]
doubles = list(map(lambda x: x * 2, numbers))
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(doubles)  # [2, 4, 6, 8, 10]
print(evens)    # [2, 4]

Annotating types: type hints

As you saw in the introduction, Python is dynamically typed: you never have to specify a variable's type. But since Python 3.5, you can annotate your variables and functions to state the type you expect. These are called type hints.

def add(a: int, b: int) -> int:
    return a + b

print(add(2, 3))   # 5

# You can annotate a variable too
age: int = 25
name: str = "Alice"
print(f"{name} is {age} years old")

The syntax is simple: a: int for a parameter, and -> int after the parentheses to declare the return type.

Note: these annotations are not checked at runtime. Python ignores them entirely when running your code: if you pass the wrong type, it still runs (or crashes later). An annotation is a hint, not a guarantee.

def add(a: int, b: int) -> int:
    return a + b

# Python does not complain, even with strings:
print(add("a", "b"))   # ab

Best practice: annotate your functions in real projects. Type hints change nothing at runtime, but they make code more readable, let your editor offer autocompletion and catch mistakes, and a tool like mypy can check the whole codebase before it runs. It's the Python equivalent of the typing we saw in JavaScript and PHP.

Avec l'IA

Copiez ce prompt dans Claude ou ChatGPT :

Écris une fonction Python qui prend une liste de nombres et renvoie un dictionnaire avec la moyenne, le minimum, le maximum et la médiane. Utilise *args pour accepter les nombres directement.
Ré-explique sans regarder

Sans relire la réponse de l'IA : avec tes mots, quelle est la différence entre *args et **kwargs, et que reçoit la fonction dans chaque cas ?

Une bonne explication dit : *args collecte les arguments positionnels en trop dans un tuple (ex. moyenne(15, 12, 18) donne notes = (15, 12, 18)) ; **kwargs collecte les arguments nommés en trop dans un dict (ex. creer_profil(nom="Alice", age=25) donne infos = {"nom": "Alice", "age": 25}). Les deux servent à accepter un nombre variable d'arguments.
Accepter ou rejeter le code de l'IA

L'IA te propose cette fonction qui ajoute un élément à une liste. Ton rôle de relecteur : l'accepter telle quelle ou la rejeter, et dire pourquoi.

def ajouter(element, panier=[]):
    panier.append(element)
    return panier
À rejeter : c'est le piège classique du paramètre par défaut mutable. La liste [] n'est créée qu'une seule fois, à la définition de la fonction, puis réutilisée à chaque appel sans argument. Résultat : ajouter(1) renvoie [1], puis ajouter(2) renvoie [1, 2] et non [2]. Le correctif standard : def ajouter(element, panier=None) puis if panier is None: panier = [] au début du corps.
Rappel libre

Sans remonter dans la leçon : quelle est la différence entre return et print() dans une fonction, et dans quel type d'objet *args regroupe-t-il les arguments ?

return renvoie une valeur à l'appelant, qu'on peut stocker dans une variable et réutiliser ; print() ne fait qu'afficher dans le terminal et renvoie None. Une fonction sans return renvoie d'ailleurs None. Et *args regroupe les arguments positionnels supplémentaires dans un tuple.
Quel mot-clé permet à une fonction de renvoyer une valeur ?
Que fait *args dans une définition de fonction ?
Que renvoie enumerate(["a", "b", "c"]) ?
Next step

Your functions work, but they forget everything once the program stops. To keep your data, we learn to read and write files, then to import modules and install packages with pip.

Lesson 6: Classes and objects →
Besoin d'un développeur pour votre projet ?

Réponse sous 24h · Sans engagement