Aller au contenu

Les modules et les packages

Introduction

En Python, les modules et les packages permettent d’organiser le code, de séparer les responsabilités et de réutiliser des fonctionnalités. Un module correspond à un fichier dont l'extension est .py, contenant des définitions, telles que des fonctions et des classes, ainsi que des instructions. Un package regroupe des modules et, éventuellement d’autres packages, dans une structure hiérarchique.

Les modules

Créer un module

Un module implémenté en Python correspond à un fichier dont l’extension est .py, contenant des fonctions, des classes, et des instructions.

Créons un fichier nommé pricing.py :

DEFAULT_TAX_RATE = 0.20

def calculate_total(price: float, tax_rate: float = DEFAULT_TAX_RATE) -> float:
    return price * (1 + tax_rate)

Le nom du module est pricing, sans l’extension .py.

Importer un module

Dans un fichier main.py, placé dans le même dossier, nous pouvons importer ce module avec le mot-clé import :

import pricing

total = pricing.calculate_total(100)

print(total)                    # 120.0
print(pricing.DEFAULT_TAX_RATE) # 0.2

Pour accéder aux éléments du module, nous préfixons leur nom par celui du module, suivi d’un point.

Importer un élément

Les mots-clés from ... import ... permettent d’utiliser directement un élément du module :

from pricing import calculate_total

total = calculate_total(100)

print(total) # 120.0

Il est également possible d’importer plusieurs éléments :

from pricing import DEFAULT_TAX_RATE, calculate_total

Définir un alias

Le mot-clé as permet d’attribuer un alias au module ou à l’élément importé :

import pricing as pr

print(pr.calculate_total(100)) # 120.0

Un alias peut aussi être appliqué à une fonction :

from pricing import calculate_total as compute_total

print(compute_total(100)) # 120.0

Il est conseillé d’éviter les imports avec *, car ils rendent plus difficile l’identification du module dont provient chaque nom et peuvent créer des conflits de noms.

Exécuter un module comme un script

Un fichier Python peut être importé ou exécuté. La variable __name__ permet de distinguer ces deux situations. Complétons le fichier pricing.py :

DEFAULT_TAX_RATE = 0.20

def calculate_total(price: float, tax_rate: float = DEFAULT_TAX_RATE) -> float:
    return price * (1 + tax_rate)

if __name__ == "__main__":
    print(calculate_total(100))

Lorsque nous exécutons ce fichier :

python pricing.py

Si la variable __name__ vaut "__main__" alors l’instruction print est exécutée. Lorsque nous importons le module, cette variable vaut "pricing"et cette instruction n’est pas exécutée.

Le code placé en dehors de ce bloc est exécuté lors du premier import du module dans le processus. Les traitements exécutés doivent donc être placés dans ce bloc.

Les packages

Créer un package

Un package permet de regrouper des modules et, éventuellement, des sous-packages. Créons les fichiers suivants :

Chemin Rôle
main.py Point d’entrée de l’application
shop/__init__.py Initialisation du package shop
shop/pricing.py Calcul des prix
shop/product.py Gestion des produits

Dans un package classique, le fichier __init__.py identifie le dossier qui le contient comme un package. Il peut rester vide ou contenir du code d’initialisation.

Python permet de créer des packages d’espace de noms sans qu'un fichier __init__.py soit présent, notamment pour répartir un package entre plusieurs emplacements.

Importer un module du package

Depuis main.py, nous pouvons importer le module pricing :

import shop.pricing

total = shop.pricing.calculate_total(100)

print(total) # 120.0

Nous pouvons aussi importer directement la fonction :

from shop.pricing import calculate_total

print(calculate_total(100)) # 120.0

Les points séparent les niveaux de la hiérarchie : shop désigne le package et pricing son module.

Définir des sous-packages

Un package peut contenir d’autres packages. Par exemple, les fichiers suivants définissent un sous-package nommé services :

Chemin Rôle
shop/services/__init__.py Initialisation du sous-package
shop/services/order_service.py Gestion des commandes

Une classe définie dans order_service.py peut être importée de cette manière :

from shop.services.order_service import OrderService

Les imports absolus et relatifs

Un import absolu indique le chemin depuis le package de premier niveau :

from shop.pricing import calculate_total

Un import relatif indique le chemin depuis le package auquel appartient le module courant.

Par exemple, dans shop/product.py, importons une fonction de l'autre module :

from .pricing import calculate_total

Le point désigne le package courant. Deux points permettent de remonter d’un niveau :

# Dans shop/services/order_service.py
from ..pricing import calculate_total

Les imports relatifs nécessitent que Python connaisse le package auquel appartient le module. Pour exécuter un module du package comme un script, nous pouvons utiliser l’option -m depuis le dossier contenant shop :

python -m shop.services.order_service

Utiliser la bibliothèque standard

Python fournit une bibliothèque standard regroupant de nombreuses fonctionnalités. Par exemple, le module math propose des fonctions mathématiques :

import math

print(math.sqrt(25)) # 5.0

D’autres modules sont disponibles, notamment json pour manipuler des documents JSON, datetime pour travailler avec les dates et heures et pathlib pour manipuler les chemins et effectuer des opérations sur les fichiers et les dossiers.

Quelques repères pour les développeurs C#

Python Repère en C#
Module Code possédant son propre espace de noms
Package Organisation hiérarchique des modules, comparable dans son usage à une organisation par namespaces. Un package Python ne correspond pas à un assembly .NET ou à un package NuGet.
import Rend un module accessible et peut exécuter son code permettant de l'initialiser
from ... import ... Importe des noms précis d’un module, utilisables sans les préfixer par le nom du module
if __name__ == "__main__": Exécute un bloc lorsque le module est utilisé comme point d’entrée, notamment avec python fichier.py ou python -m package.module.