La programmation modulaire avec des fonctions

PythonPythonBeginner
Pratiquer maintenant

This tutorial is from open-source community. Access the source code

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

Cette section présente le concept de modules et la manipulation de fonctions qui s'étendent sur plusieurs fichiers.

Modules et importation

Tout fichier source Python est un module.

## foo.py
def grok(a):
  ...
def spam(b):
  ...

L'instruction import charge et exécute un module.

## program.py
import foo

a = foo.grok(2)
b = foo.spam('Hello')
...

Espaces de noms

Un module est une collection de valeurs nommées et est parfois appelé un espace de noms. Les noms sont toutes les variables globales et les fonctions définies dans le fichier source. Après l'importation, le nom du module est utilisé comme préfixe. D'où l'espace de noms.

import foo

a = foo.grok(2)
b = foo.spam('Hello')
...

Le nom du module est directement lié au nom de fichier (foo -> foo.py).

Définitions globales

Tout ce qui est défini dans l'espace de portée globale est ce qui remplit l'espace de noms du module. Considérez deux modules qui définissent la même variable x.

## foo.py
x = 42
def grok(a):
 ...
## bar.py
x = 37
def spam(a):
 ...

Dans ce cas, les définitions de x se réfèrent à des variables différentes. L'une est foo.x et l'autre est bar.x. Différents modules peuvent utiliser les mêmes noms et ces noms ne se conflitent pas les uns avec les autres.

Les modules sont isolés.

Les modules comme environnements

Les modules forment un environnement entourant tout le code défini à l'intérieur.

## foo.py
x = 42

def grok(a):
    print(x)

Les variables globales sont toujours liées au module entourant (même fichier). Chaque fichier source est son propre petit univers.

Exécution du module

Lorsque l'on importe un module, toutes les instructions du module s'exécutent les unes après les autres jusqu'à la fin du fichier. Le contenu de l'espace de noms du module est tous les noms globaux qui sont encore définis à la fin du processus d'exécution. Si vous avez des instructions de script qui effectuent des tâches dans l'espace de portée globale (affichage, création de fichiers, etc.), vous les verrez s'exécuter lors de l'importation.

Instruction import as

Vous pouvez modifier le nom d'un module lors de son importation :

import math as m
def rectangular(r, theta):
    x = r * m.cos(theta)
    y = r * m.sin(theta)
    return x, y

Ça fonctionne de la même manière qu'un import normal. Il ne fait que renommer le module dans ce fichier-là.

Importation à partir d'un module (from)

Cela permet de sélectionner des symboles d'un module et de les rendre disponibles localement.

from math import sin, cos

def rectangular(r, theta):
    x = r * cos(theta)
    y = r * sin(theta)
    return x, y

Cela permet d'utiliser des parties d'un module sans avoir à taper le préfixe du module. C'est pratique pour les noms utilisés fréquemment.

Commentaires sur l'importation

Les variations de l'importation ne changent pas la manière dont les modules fonctionnent.

import math
## vs
import math as m
## vs
from math import cos, sin
...

Plus précisément, import exécute toujours tout le fichier et les modules restent des environnements isolés.

L'instruction import module as ne fait que changer le nom localement. L'instruction from math import cos, sin charge toujours le module mathématique en arrière-plan. Elle ne fait que copier les noms cos et sin du module dans l'espace local une fois qu'elle est terminée.

Chargement des modules

Chaque module ne se charge et n'est exécuté qu'une seule fois. Remarque : Les importations répétées ne renvoient simplement qu'une référence au module chargé précédemment.

sys.modules est un dictionnaire de tous les modules chargés.

>>> import sys
>>> sys.modules.keys()
['copy_reg', '__main__','site', '__builtin__', 'encodings', 'encodings.encodings', 'posixpath',...]
>>>

Attention : Une erreur fréquente se produit si vous répétez une instruction import après avoir modifié le code source d'un module. En raison du cache des modules sys.modules, les importations répétées renvoient toujours le module chargé précédemment - même si un changement a été effectué. Le moyen le plus sûr de charger le code modifié dans Python est d'arrêter et de redémarrer l'interpréteur.

Recherche des modules

Python consulte une liste de chemins (sys.path) lorsqu'il recherche des modules.

>>> import sys
>>> sys.path
[
  '',
  '/usr/local/lib/python36/python36.zip',
  '/usr/local/lib/python36',
...
]

Le répertoire de travail actuel est généralement le premier.

Chemin de recherche des modules

Comme indiqué, sys.path contient les chemins de recherche. Vous pouvez l'ajuster manuellement si nécessaire.

import sys
sys.path.append('/project/foo/pyfiles')

Les chemins peuvent également être ajoutés via des variables d'environnement.

% env PYTHONPATH=/project/foo/pyfiles python3
Python 3.6.0 (default, Feb 3 2017, 05:53:21)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)]
>>> import sys
>>> sys.path
['','/project/foo/pyfiles',...]

En règle générale, il n'est pas nécessaire d'ajuster manuellement le chemin de recherche des modules. Cependant, cela peut arriver si vous essayez d'importer du code Python situé dans un emplacement inhabituel ou difficilement accessible depuis le répertoire de travail actuel.

Pour cet exercice sur les modules, il est crucial de vous assurer que vous exécutez Python dans un environnement approprié. Les modules posent souvent des problèmes aux nouveaux programmeurs liés au répertoire de travail actuel ou aux paramètres de chemin de Python. Pour ce cours, il est supposé que vous écrivez tout votre code dans le répertoire ~/project. Pour obtenir les meilleurs résultats, vous devriez vous assurer également d'être dans ce répertoire lorsque vous lancez l'interpréteur. Sinon, vous devez vous assurer que ~/project est ajouté à sys.path.

Exercice 3.11 : Importations de modules

Dans la section 3, nous avons créé une fonction générale parse_csv() pour analyser le contenu de fichiers de données au format CSV.

Maintenant, nous allons voir comment utiliser cette fonction dans d'autres programmes. Commencez par ouvrir une nouvelle fenêtre de terminal. Naviguez vers le dossier où se trouvent tous vos fichiers. Nous allons les importer.

Démarrez le mode interactif de Python.

$ python3
Python 3.6.1 (v3.6.1:69c0db5050, Mar 21 2017, 01:21:04)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

Une fois que vous avez fait cela, essayez d'importer certains des programmes que vous avez précédemment écrits. Vous devriez voir leur sortie exactement comme avant. Pour souligner, importer un module exécute son code.

>>> import bounce
... observez la sortie...
>>> import mortgage
... observez la sortie...
>>> import report
... observez la sortie...
>>>

Si rien de cela ne fonctionne, vous êtes probablement exécutant Python dans le mauvais répertoire. Maintenant, essayez d'importer votre module fileparse et d'obtenir de l'aide sur celui-ci.

>>> import fileparse
>>> help(fileparse)
... regardez la sortie...
>>> dir(fileparse)
... regardez la sortie...
>>>

Essayez d'utiliser le module pour lire certaines données :

>>> portfolio = fileparse.parse_csv('/home/labex/project/portfolio.csv',select=['name','shares','price'], types=[str,int,float])
>>> portfolio
... regardez la sortie...
>>> pricelist = fileparse.parse_csv('/home/labex/project/prices.csv',types=[str,float], has_headers=False)
>>> pricelist
... regardez la sortie...
>>> prices = dict(pricelist)
>>> prices
... regardez la sortie...
>>> prices['IBM']
106.28
>>>

Essayez d'importer une fonction pour ne pas avoir besoin d'inclure le nom du module :

>>> from fileparse import parse_csv
>>> portfolio = parse_csv('/home/labex/project/portfolio.csv', select=['name','shares','price'], types=[str,int,float])
>>> portfolio
... regardez la sortie...
>>>

Exercice 3.12 : Utilisation de votre module de bibliothèque

Dans la section 2, vous avez écrit un programme report.py qui produisait un rapport sur les actions comme ceci :

      Nom     Actions      Prix     Changement
---------- ---------- ---------- ----------
        AA        100       9.22     -22.98
       IBM         50     106.28      15.18
       CAT        150      35.46     -47.98
      MSFT        200      20.89     -30.34
        GE         95      13.48     -26.89
      MSFT         50      20.89     -44.21
       IBM        100     106.28      35.84

Prenez ce programme et modifiez-le de sorte que tout le traitement des fichiers d'entrée soit effectué à l'aide de fonctions dans votre module fileparse. Pour ce faire, importez fileparse en tant que module et modifiez les fonctions read_portfolio() et read_prices() pour utiliser la fonction parse_csv().

Utilisez l'exemple interactif au début de cet exercice comme guide. Ensuite, vous devriez obtenir exactement la même sortie qu'avant.

✨ Vérifier la solution et pratiquer

Exercice 3.13 : Intentionnellement laissé vide (passez)

Exercice 3.14 : Utilisation de plus d'importations de bibliothèque

Dans la section 1, vous avez écrit un programme pcost.py qui lisait un portefeuille et calculait son coût.

>>> import pcost
>>> pcost.portfolio_cost('/home/labex/project/portfolio.csv')
44671.15
>>>

Modifiez le fichier pcost.py de sorte qu'il utilise la fonction report.read_portfolio().

✨ Vérifier la solution et pratiquer

Commentaire

Lorsque vous avez terminé cet exercice, vous devriez avoir trois programmes. fileparse.py qui contient une fonction générale parse_csv(). report.py qui produit un bel état, mais contient également les fonctions read_portfolio() et read_prices(). Et enfin, pcost.py qui calcule le coût du portefeuille, mais utilise la fonction read_portfolio() écrite pour le programme report.py.

Sommaire

Félicitations ! Vous avez terminé le laboratoire sur les modules. Vous pouvez pratiquer d'autres laboratoires sur LabEx pour améliorer vos compétences.