Modules et packages


In programming, un module est un morceau de logiciel qui possède une fonctionnalité spécifique. Par exemple, lors de la création d'un jeu de ping-pong, un module peut être responsable de la logique du jeu, et un autre module dessine le jeu à l'écran. Chaque module est constitué d'un fichier différent, qui peut être modifié séparément.

Écriture de modules

Les modules en Python sont simplement des fichiers Python avec une extension .py. Le nom du module est le même que le nom du fichier. Un module Python peut avoir un ensemble de fonctions, de classes ou de variables définies et implémentées. L'exemple ci-dessus comprend deux fichiers :

mygame/

  • mygame/game.py

  • mygame/draw.py

Le script Python game.py implémente le jeu. Il utilise la fonction draw_game à partir du fichier draw.py, ou en d'autres termes, le module draw qui implémente la logique pour dessiner le jeu à l'écran.

Les modules sont importés d'autres modules en utilisant la commande import. Dans cet exemple, le script game.py pourrait ressembler à ceci :

# game.py
# import the draw module
import draw

def play_game():
    ...

def main():
    result = play_game()
    draw.draw_game(result)

# cela signifie que si ce script est exécuté, alors 
# main() sera exécuté
if __name__ == '__main__':
    main()

Le module draw pourrait ressembler à ceci :

# draw.py

def draw_game():
    ...

def clear_screen(screen):
    ...

Dans cet exemple, le module game importe le module draw, ce qui permet d'utiliser les fonctions implémentées dans ce module. La fonction main utilise la fonction locale play_game pour lancer le jeu, puis dessine le résultat du jeu en utilisant une fonction implémentée dans le module draw appelée draw_game. Pour utiliser la fonction draw_game du module draw, nous devons spécifier dans quel module la fonction est implémentée, en utilisant l'opérateur point. Pour référencer la fonction draw_game depuis le module game, nous devons importer le module draw puis appeler draw.draw_game().

Lorsque la directive import draw s'exécute, l'interpréteur Python recherche un fichier dans le répertoire dans lequel le script a été exécuté avec le nom du module et un suffixe .py. Dans ce cas, il cherchera draw.py. S'il est trouvé, il sera importé. S'il n'est pas trouvé, il continuera à chercher dans les modules intégrés.

Vous avez peut-être remarqué que lors de l'importation d'un module, un fichier .pyc est créé. Il s'agit d'un fichier Python compilé. Python compile les fichiers en bytecode Python afin qu'il n'ait pas à analyser les fichiers à chaque fois que les modules sont chargés. Si un fichier .pyc existe, il est chargé à la place du fichier .py. Ce processus est transparent pour l'utilisateur.

Importation d'objets de module dans l'espace de noms actuel

Un espace de noms est un système où chaque objet est nommé et peut être accédé en Python. Nous importons la fonction draw_game dans l'espace de noms du script principal en utilisant la commande from.

# game.py
# import the draw module
from draw import draw_game

def main():
    result = play_game()
    draw_game(result)

Vous avez peut-être remarqué que dans cet exemple, le nom du module ne précède pas draw_game, car nous avons spécifié le nom du module en utilisant la commande import.

Les avantages de cette notation sont que vous n'avez pas à référencer le module sans cesse. Cependant, un espace de noms ne peut pas avoir deux objets avec le même nom, donc la commande import peut remplacer un objet existant dans l'espace de noms.

Importation de tous les objets d'un module

Vous pouvez utiliser la commande import * pour importer tous les objets d'un module comme ceci :

# game.py
# import the draw module
from draw import *

def main():
    result = play_game()
    draw_game(result)

Cela peut être un peu risqué car les modifications du module peuvent affecter le module qui l'importe, mais c'est plus court, et cela ne nécessite pas de spécifier chaque objet que vous voulez importer du module.

Nom d'importation personnalisé

Les modules peuvent être chargés sous n'importe quel nom que vous souhaitez. Cela est utile lors de l'importation conditionnelle d'un module pour utiliser le même nom dans le reste du code.

Par exemple, si vous avez deux modules draw avec des noms légèrement différents, vous pouvez faire ce qui suit :

# game.py
# import the draw module
if visual_mode:
    # en mode visuel, nous dessinons en utilisant des graphiques
    import draw_visual as draw
else:
    # en mode textuel, nous affichons du texte
    import draw_textual as draw

def main():
    result = play_game()
    # cela peut être visuel ou textuel selon le mode visuel
    draw.draw_game(result)

Initialisation des modules

La première fois qu'un module est chargé dans un script Python en cours d'exécution, il est initialisé en exécutant le code dans le module une seule fois. Si un autre module dans votre code réimporte le même module, il ne sera pas rechargé, donc les variables locales à l'intérieur du module agissent comme un "singleton", ce qui signifie qu'elles sont initialisées une seule fois.

Vous pouvez ensuite utiliser cela pour initialiser des objets. Par exemple :

# draw.py

def draw_game():
    # lors du nettoyage de l'écran, nous pouvons utiliser l'objet écran principal initialisé dans ce module
    clear_screen(main_screen)
    ...

def clear_screen(screen):
    ...

class Screen():
    ...

# initialiser main_screen en tant que singleton
main_screen = Screen()

Extension du chemin de chargement des modules

Il existe quelques méthodes pour indiquer à l'interpréteur Python où rechercher les modules, en dehors du répertoire local par défaut et des modules intégrés. Vous pouvez utiliser la variable d'environnement PYTHONPATH pour spécifier des répertoires supplémentaires pour rechercher les modules comme ceci :

PYTHONPATH=/foo python game.py

Cela exécute game.py, et permet au script de charger des modules à partir du répertoire foo, ainsi que du répertoire local.

Vous pouvez également utiliser la fonction sys.path.append. Exécutez-la avant de lancer la commande import :

sys.path.append("/foo")

Maintenant, le répertoire foo a été ajouté à la liste des chemins où les modules sont recherchés.

Exploration des modules intégrés

Consultez la liste complète des modules intégrés dans la bibliothèque standard Python ici.

Deux fonctions très importantes sont utiles lors de l'exploration des modules en Python : les fonctions dir et help.

Pour importer le module urllib, qui nous permet de lire les données des URL, nous importons le module :

# import the library
import urllib

# use it
urllib.urlopen(...)

Nous pouvons rechercher quelles fonctions sont implémentées dans chaque module en utilisant la fonction dir :

>>> import urllib
>>> dir(urllib)
['ContentTooShortError', 'FancyURLopener', 'MAXFTPCACHE', 'URLopener', '__all__', '__builtins__', 
'__doc__', '__file__', '__name__', '__package__', '__version__', '_ftperrors', '_get_proxies', 
'_get_proxy_settings', '_have_ssl', '_hexdig', '_hextochr', '_hostprog', '_is_unicode', '_localhost', 
'_noheaders', '_nportprog', '_passwdprog', '_portprog', '_queryprog', '_safe_map', '_safe_quoters', 
'_tagprog', '_thishost', '_typeprog', '_urlopener', '_userprog', '_valueprog', 'addbase', 'addclosehook', 
'addinfo', 'addinfourl', 'always_safe', 'basejoin', 'c', 'ftpcache', 'ftperrors', 'ftpwrapper', 'getproxies', 
'getproxies_environment', 'getproxies_macosx_sysconf', 'i', 'localhost', 'main', 'noheaders', 'os', 
'pathname2url', 'proxy_bypass', 'proxy_bypass_environment', 'proxy_bypass_macosx_sysconf', 'quote', 
'quote_plus', 'reporthook', 'socket', 'splitattr', 'splithost', 'splitnport', 'splitpasswd', 'splitport', 
'splitquery', 'splittag', 'splittype', 'splituser', 'splitvalue', 'ssl', 'string', 'sys', 'test', 'test1', 
'thishost', 'time', 'toBytes', 'unquote', 'unquote_plus', 'unwrap', 'url2pathname', 'urlcleanup', 'urlencode', 
'urlopen', 'urlretrieve']

Lorsque nous trouvons la fonction dans le module que nous voulons utiliser, nous pouvons en lire plus à son sujet avec la fonction help, en utilisant l'interpréteur Python :

help(urllib.urlopen)

Écriture de packages

Les packages sont des espaces de noms contenant plusieurs packages et modules. Ce sont simplement des répertoires, mais avec certaines exigences.

Chaque package en Python est un répertoire qui DOIT contenir un fichier spécial appelé __init__.py. Ce fichier, qui peut être vide, indique que le répertoire dans lequel il se trouve est un package Python. Ainsi, il peut être importé de la même manière qu'un module.

Si nous créons un répertoire appelé foo, qui marque le nom du package, nous pouvons ensuite créer un module à l'intérieur de ce package appelé bar. Ensuite, nous ajoutons le fichier __init__.py à l'intérieur du répertoire foo.

Pour utiliser le module bar, nous pouvons l'importer de deux manières :

import foo.bar

ou :

from foo import bar

Dans le premier exemple ci-dessus, nous devons utiliser le préfixe foo chaque fois que nous accédons au module bar. Dans le second exemple, ce n'est pas nécessaire, car nous avons importé le module dans l'espace de noms de notre module.

Le fichier __init__.py peut également décider quels modules le package exporte en tant qu'API, tout en gardant d'autres modules internes, en modifiant la variable __all__ comme suit :

__init__.py:

__all__ = ["bar"]

Exercice

Dans cet exercice, imprimez une liste triée alphabétiquement de toutes les fonctions du module re contenant le mot find.


Copyright © learnpython.org. Read our Terms of Use and Privacy Policy