Organisation de programmes Python plus importants

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

Si vous écrivez un programme plus important, vous ne voulez pas vraiment l'organiser comme une grande collection de fichiers indépendants au niveau supérieur. Cette section présente le concept d'un package.

Modules

Tout fichier source Python est un module.

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

Une instruction import charge et exécute un module.

## program.py
import foo

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

Packages vs Modules

Pour de plus grandes collections de code, il est courant d'organiser les modules en un package.

## De cela
pcost.py
report.py
fileparse.py

## A cela
porty/
    __init__.py
    pcost.py
    report.py
    fileparse.py

Vous choisissez un nom et créez un répertoire de niveau supérieur. porty dans l'exemple ci-dessus (choisir ce nom est clairement la première étape la plus importante).

Ajoutez un fichier __init__.py au répertoire. Il peut être vide.

Placez vos fichiers sources dans le répertoire.

Using a Package

Un package sert de nommage pour les importations.

Cela signifie qu'il existe désormais des importations multi-niveaux.

import porty.report
port = porty.report.read_portfolio('portfolio.csv')

Il existe d'autres variantes d'instructions d'importation.

from porty import report
port = report.read_portfolio('portfolio.csv')

from porty.report import read_portfolio
port = read_portfolio('portfolio.csv')

Two problems

Il y a deux principaux problèmes avec cette approche.

  • Les importations entre fichiers dans le même package ne fonctionnent plus.
  • Les scripts principaux placés à l'intérieur du package ne fonctionnent plus.

Donc, fondamentalement, tout ne fonctionne plus. Mais, hormis ça, ça marche.

Problem: Imports

Les importations entre fichiers dans le même package doivent désormais inclure le nom du package dans l'import. Rappelez-vous la structure.

porty/
    __init__.py
    pcost.py
    report.py
    fileparse.py

Exemple d'import modifié.

from porty import fileparse

def read_portfolio(filename):
    return fileparse.parse_csv(...)

Toutes les importations sont absolues, pas relatives.

import fileparse    ## NE FONCTIONNE PAS. fileparse non trouvé

...

Importations relatives

Au lieu d'utiliser directement le nom du package, vous pouvez utiliser . pour vous référer au package actuel.

from. import fileparse

def read_portfolio(filename):
    return fileparse.parse_csv(...)

Syntaxe :

from. import modname

Cela facilite la renommation du package.

Problem: Main Scripts

Exécuter un sous-module de package en tant que script principal ne fonctionne pas.

$ python porty/pcost.py ## NE FONCTIONNE PAS
...

Raison : Vous exécutez Python sur un seul fichier et Python ne voit pas correctement le reste de la structure du package (sys.path est incorrect).

Toutes les importations ne fonctionnent pas. Pour résoudre ce problème, vous devez exécuter votre programme d'une manière différente, en utilisant l'option -m.

$ python -m porty.pcost ## FONCTIONNE
...

Fichiers __init__.py

Le principal but de ces fichiers est de rassembler les modules.

Exemple : consolidation de fonctions

## porty/__init__.py
from.pcost import portfolio_cost
from.report import portfolio_report

Cela permet d'avoir les noms disponibles au niveau supérieur lors de l'importation.

from porty import portfolio_cost
portfolio_cost('portfolio.csv')

Plutôt que d'utiliser des importations multi-niveaux.

from porty import pcost
pcost.portfolio_cost('portfolio.csv')

Une autre solution pour les scripts

Comme indiqué, vous devez désormais utiliser -m package.module pour exécuter les scripts dans votre package.

$ python3 -m porty.pcost portfolio.csv

Il existe une autre alternative : écrire un nouveau script de niveau supérieur.

#!/usr/bin/env python3
## pcost.py
import porty.pcost
import sys
porty.pcost.main(sys.argv)

Ce script se trouve en dehors du package. Par exemple, en examinant la structure de répertoire :

pcost.py       ## script de niveau supérieur
porty/         ## répertoire du package
    __init__.py
    pcost.py
 ...

Structure d'application

L'organisation du code et la structure des fichiers sont clés pour la maintenabilité d'une application.

Il n'y a pas d'approche "unique" pour Python. Cependant, une structure qui fonctionne pour de nombreux problèmes est la suivante.

porty-app/
  README.txt
  script.py         ## SCRIPT
  porty/
    ## CODE DE BIBLIOTHÈQUE
    __init__.py
    pcost.py
    report.py
    fileparse.py

Le niveau supérieur porty-app est un conteneur pour tout le reste - la documentation, les scripts de niveau supérieur, les exemples, etc.

Encore une fois, les scripts de niveau supérieur (s'il y en a) doivent exister en dehors du package de code. Un niveau au-dessus.

#!/usr/bin/env python3
## porty-app/script.py
import sys
import porty

porty.report.main(sys.argv)

À ce stade, vous avez un répertoire avec plusieurs programmes :

pcost.py          ## calcule le coût d'un portefeuille
report.py         ## Génère un rapport
ticker.py         ## Génère un indice boursier en temps réel

Il existe une variété de modules d'assistance avec d'autres fonctionnalités :

stock.py          ## Classe Stock
portfolio.py      ## Classe Portfolio
fileparse.py      ## Analyse CSV
tableformat.py    ## Tableaux formatés
follow.py         ## Suivre un fichier de journal
typedproperty.py  ## Propriétés de classe typées

Dans cet exercice, nous allons nettoyer le code et le placer dans un package commun.

Exercice 9.1 : Création d'un package simple

Créez un répertoire appelé porty/ et placez tous les fichiers Python ci-dessus à l'intérieur. Créez également un fichier __init__.py vide et placez-le dans le répertoire. Vous devriez avoir un répertoire de fichiers comme ceci :

porty/
    __init__.py
    fileparse.py
    follow.py
    pcost.py
    portfolio.py
    report.py
    stock.py
    tableformat.py
    ticker.py
    typedproperty.py

Supprimez le fichier __pycache__ qui se trouve dans votre répertoire. Celui-ci contient des modules Python pré-compilés antérieurement. Nous voulons commencer avec un état vierge.

Essayez d'importer certains des modules du package :

>>> import porty.report
>>> import porty.pcost
>>> import porty.ticker

Si ces importations échouent, accédez au fichier approprié et corrigez les importations de module pour inclure une importation relative au package. Par exemple, une instruction telle que import fileparse pourrait devenir la suivante :

## report.py
from. import fileparse

...

Si vous avez une instruction telle que from fileparse import parse_csv, changez le code en :

## report.py
from.fileparse import parse_csv

...

✨ Vérifier la solution et pratiquer

Exercice 9.2 : Création d'un répertoire d'application

Placer tout votre code dans un "package" n'est souvent pas suffisant pour une application. Parfois, il y a des fichiers d'assistance, de la documentation, des scripts et autres éléments. Ces fichiers doivent exister EN DEHORS du répertoire porty/ que vous avez créé ci-dessus.

Créez un nouveau répertoire appelé porty-app. Déplacez le répertoire porty que vous avez créé dans l'Exercice 9.1 dans ce répertoire. Copiez les fichiers de test portfolio.csv et prices.csv dans ce répertoire. Créez également un fichier README.txt avec quelques informations sur vous-même. Votre code devrait maintenant être organisé comme suit :

porty-app/
    portfolio.csv
    prices.csv
    README.txt
    porty/
        __init__.py
        fileparse.py
        follow.py
        pcost.py
        portfolio.py
        report.py
        stock.py
        tableformat.py
        ticker.py
        typedproperty.py

Pour exécuter votre code, vous devez vous assurer d'être dans le répertoire porty-app/ de niveau supérieur. Par exemple, à partir du terminal :

$ cd porty-app
$ python3
>>> import porty.report
>>>

Essayez d'exécuter certains de vos scripts antérieurs en tant que programme principal :

$ cd porty-app
$ python3 -m porty.report portfolio.csv prices.csv txt
      Name     Shares      Price     Change
---------- ---------- ---------- ----------
        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

$

Exercice 9.3 : Scripts de niveau supérieur

Utiliser la commande python -m est souvent un peu étrange. Vous pouvez vouloir écrire un script de niveau supérieur qui traite simplement les particularités des packages. Créez un script print-report.py qui produit le rapport ci-dessus :

#!/usr/bin/env python3
## print-report.py
import sys
from porty.report import main
main(sys.argv)

Placez ce script dans le répertoire porty-app/ de niveau supérieur. Assurez-vous de pouvoir l'exécuter à cet emplacement :

$ cd porty-app
$ python3 print-report.py portfolio.csv prices.csv txt
      Name     Shares      Price     Change
---------- ---------- ---------- ----------
        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

$

Votre code final devrait maintenant être structuré comme ceci :

porty-app/
    portfolio.csv
    prices.csv
    print-report.py
    README.txt
    porty/
        __init__.py
        fileparse.py
        follow.py
        pcost.py
        portfolio.py
        report.py
        stock.py
        tableformat.py
        ticker.py
        typedproperty.py
✨ Vérifier la solution et pratiquer

Sommaire

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