đ Python Input/Output#
Python et les fichiers#
La fonction open()
renvoie un objet de type file
et est le plus souvent utilisée avec deux arguments : open(nomfichier, mode)
.
workfile = open('workfile', 'w')
Câest une bonne pratique dâutiliser le mot-clĂ© with
lorsque vous traitez des fichiers. Vous fermez ainsi toujours correctement le fichier, mĂȘme si une exception est levĂ©e. Utiliser with
est aussi beaucoup plus court que dâutiliser lâĂ©quivalent avec des blocs try-finally
:
with open('workfile') as workfile:
read_data = workfile.read() # read all file content as a string
lines = workfile.readlines() # read all lines and store them in a list
with open('writefile', 'w') as writefile:
writefile.write('Hello World')
Avertissement
Si vous nâutilisez pas le mot clef with
, vous devez appeler workfile.close()
pour fermer le fichier et immĂ©diatement libĂ©rer les ressources systĂšme quâil utilise.
Indication
Les modules os
et os.path
permettent de manipuler facilement des fichiers.
import os
os.remove('workfile') # Delete workfile
os.path.exists('workfile') # Return True if workfile exist else False
os.path.getsize('workfile') # Return file size
os.path.isfile('workfile') # Return True if workfile is a file
Fichier CSV et Python#
Comma-separated values
Comma-separated values, connu sous le sigle CSV
, est un format texte ouvert reprĂ©sentant des donnĂ©es tabulaires sous forme de valeurs sĂ©parĂ©es par des virgules. Le format fut utilisĂ© pendant des annĂ©es avant quâaient lieu des tentatives de standardisation avec la RFC 4180. Lâabsence de format bien dĂ©fini signifie que des diffĂ©rences subtiles existent dans la production et la consommation de donnĂ©es par diffĂ©rentes applications. Ces diffĂ©rences peuvent gĂȘner lors du traitement de fichiers CSV depuis des sources multiples.
ref.,name,price,release-date
IEL-51619,Ishtar - Les Jardins De Babylone,40.0,2019-10-04
BLU-KIN01,Kingdomino,19.90,2016-10-21
BO-DRA01,Draftosaurus,19.90,2019-02-22
FLY004JU,Jurassic Snack,19.90,2018-04-06
ref. |
name |
price |
release-date |
---|---|---|---|
IEL-51619 |
Ishtar - Les Jardins De Babylone |
40.0 |
2019-10-04 |
BLU-KIN01 |
Kingdomino |
19.90 |
2016-10-21 |
BO-DRA01 |
Draftosaurus |
19.90 |
2019-02-22 |
FLY004JU |
Jurassic Snack |
19.90 |
2018-04-06 |
Note
Le dĂ©limiteur de colonnes peut ĂȘtre autre chose quâune virgule, il arrive frĂ©quemment dâutiliser le point-virgule plutĂŽt que la virgule comme dĂ©limiteur.
Le module csv
fournit des classes pour lire et écrire des données tabulaires au format CSV.
import csv
with open('eggs.csv') as csvfile:
reader = csv.reader(csvfile, delimiter='|')
for row in reader:
print(row)
import csv
with open('eggs.csv', 'w') as csvfile:
writer = csv.writer(csvfile, delimiter='|')
writer.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])
writer.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])
Indication
Les classes DictReader
et DictWriter
permettent de travailler sur des dictionnaires plutÎt que sur des séquences.
Créer un CLI#
Lâutilisation du module argparse
comme module « dâanalyse dâarguments de ligne de commande » est recommandĂ© et est disponible dans la bibliothĂšque standard Python.
import argparse
parser = argparse.ArgumentParser(description="This is a usefull description")
parser.add_argument("echo", help="echo the string you use here")
parser.add_argument("square", help="display a square of a given number", type=int)
parser.add_argument("---verbosity", help="increase output verbosity") # optionnal args
args = parser.parse_args()
print(args.echo)
print(args.square)
Le module atexit
permet dâenregistrer des appels de fonctions Ă faire en sortie dâun programme pour faire le « mĂ©nage ». Les fonctions sont appelĂ©es :
en sortie « normale » de programme, y compris avec un
sys.exit(1)
par exemple.si le programme se termine Ă cause dâune exception.
si le programme se termine Ă cause dâune erreur python (fonction appelĂ©e non existante, ou Ă©valuation de None + 1 par exemple).
si on fait un
ctrl + C
pour interrompre le programme (SIGINT
).mais pas dâappel si on tue le programme par
SIGTERM
(kill -15
) ouSIGKILL
(kill -9
).
import atexit
def close_connection(connection):
if connection:
connection.close()
atexit.register(close_connection, connection)
Le module sqlite3
#
Le module sqlite3
, intégré dans la bibliothÚque standard de Python, a été écrit par Gerhard HÀring. Il fournit une interface SQL
conforme à la spécification DB-API 2.0 décrite par la PEP 249.
Note
DB-API 2.0
est une API définie pour encourager la similarité entre les modules Python utilisés pour accéder aux bases de données.
Nous nâallons pas ici dĂ©tailler la spĂ©cification DB-API 2.0
mais décrire comment utilisé succinctement le module sqlite3
.
SQLite#
l sâagit dâune bibliothĂšque Ă©crite en langage C
. Elle propose un moteur de base de données relationnelles accessible par le langage SQL
, et implémente le standard SQL-92
et les propriétés ACID
. Ce moteur est développé depuis 2000 D. Richard Hipp. La bibliothÚque ainsi que son code source sont sous la licence du domaine public.
- Particularité
Sa particularitĂ© est de ne pas reproduire le schĂ©ma habituel client-serveur mais dâĂȘtre directement intĂ©grĂ©e aux programmes. LâaccĂšs Ă une base de donnĂ©es avec SQLite se fait par lâouverture du fichier correspondant Ă celle-ci. Chaque base de donnĂ©es est enregistrĂ©e dans un fichier qui lui est propre, avec ses dĂ©clarations, ses tables et ses index mais aussi ses donnĂ©es.
Il nây a pas dâextension propre aux fichiers de base de donnĂ©es de SQLite, il est courant de rencontrer des extensions comme
.sqlite
ou.db
, parfois suivie du numéro de version de la bibliothÚque (.sqlite3
,.db2
, etc.).- Popularité
Il sâagit dâun des moteurs de bases de donnĂ©es les plus utilisĂ©s au monde, celui-ci est notamment utilisĂ© par Firefox, Skype, Google Gears, Android, iOS, des sites web, etc.
Une des raisons de son succĂšs est quâelle est intĂ©grĂ©e dans les bibliothĂšques standard de nombreux langages comme
Python, Ruby, PHP, C#, C++, etc.
De plus son extrĂȘme lĂ©gĂšretĂ© (moins de 600 Kio), la rende populaire sur les systĂšmes embarquĂ©s.- PortabilitĂ©
Ătant entiĂšrement Ă©crite en
C-ANSI
, la version normalisée du langage de programmationC
, celle-ci est compilable sans modification sur toutes les architectures,Ainsi les fichiers de base de donnĂ©es SQLite sont entiĂšrement indĂ©pendants du systĂšme dâexploitation et de lâarchitecture.
- Type de données
Il existe plusieurs types dâaffinitĂ© dans SQLite, dĂ©finissant la façon dont celui-ci va travailler lors de lâentrĂ©e des nouvelles donnĂ©es.
TEXT NUMERIC INTEGER REAL NONE
Note
Une interface en ligne de commande (en anglais command line interface, couramment abrĂ©gĂ©e CLI) est une interface homme-machine dans laquelle la communication entre lâutilisateur et lâordinateur sâeffectue en mode texte au sein dâun terminal (console).
SQLite embarque une interface en ligne de commande (CLI) simple et pratique pour crĂ©er et requĂȘter sur une base de donnĂ©es SQLite. Son utilisation se fait simplement par la commande sqlite3
$ sqlite3 -version
3.26.0 2018-12-01 12:34:55 bf8c1b2b7a5960c282e543b9c293686dccff272512d08865f4600fb58238alt1
.exit --Permet de quitter la commande CLI
.table --Liste l'ensemble des tables de la base
.dbinfo --Information sur la base
.dump --Obtenir un dump sql de la base
.schema --Obtenir le code de création de la base
.headers (on, off) --Affichage ou non des entĂȘtes
.mode (list, column, csv, ..) --Affichage en liste, etc.
.version --Information de version
.import --Import de données dans la base
Pour se conncter Ă une base de donnĂ©es, il suffit dâindiquer le nom du fichier de base de donnĂ©es en argument de la commande sqlite3
:
$ sqlite3 boardgames.sqlite3
Attention
Si le fichier existe alors la commande ouvre la base de données sinon celle-ci est créée avant ouverture.
Indication
Voici quelques astuces utiles avec la commande sqlite3
Ă faire aprĂšs chaque lancement de la commande:
$ sqlite3 boardgames.sqlite3
sqlite> .headers on -- Display column name
sqlite> .mode columns -- Change display mode, try it
sqlite> .tables -- Show all db tables
sqlite> PRAGMA table_info(nom_table); -- Show structure of nom_table
Il est recommandĂ© d'Ă©crire les requĂȘtes (de crĂ©ation de tables par exemple) dans un fichier :code:`.sql` et de le jouer ensuite via la commande :code:`sqlite3`
.. code-block:: bash
$ sqlite3 boardgames.sqlite3
sqlite> .read creation_schema.sql
Rappel de SQL#
CREATE TABLE contacts (
id INTEGER PRIMARY KEY,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
email TEXT,
phone TEXT NOT NULL CHECK (length(phone) >= 10)
);
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
list_price DECIMAL (10, 2) NOT NULL,
discount DECIMAL (10, 2) NOT NULL
DEFAULT 0,
CHECK (list_price >= discount AND
discount >= 0 AND
list_price >= 0)
);
/* Sélection */
SELECT [ * / columns_name ] FROM tablename;
/* Compter */
SELECT COUNT(column_name) FROM table_name;
/* Trier */
SELECT column_name(s) FROM table_name ORDER BY column_name(s) ASC|DESC;
/* INSERTION */
INSERT INTO table_name (column1, column2, column3,...) VALUES (value1, value2, value3,...);
/* MAJ */
UPDATE table_name SET column1=value, column2=value2,... WHERE some_column=some_value;
/* SUPPRESSION */
DELETE FROM table_name WHERE some_column=somevalue;
\end{minted}
Utilisation du module sqlite3
#
Pour utiliser le module, vous devez dâabord crĂ©er une instance de la classe Connection
qui représente la base de données.
Dans cet exemple, les données sont stockées dans le fichier example.sqlite3
:
import sqlite3
connection = sqlite3.connect('example.sqlite3')
Une fois que vous avez une instance de Connection
, vous pouvez créer un objet Cursor
et appeler sa méthode execute()
pour exécuter des commandes SQL :
cursor = connection.cursor()
# Create table
cursor.execute('''CREATE TABLE stocks
(date text, trans text, symbol text, qty real, price real)''')
# Insert a row of data
cursor.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)")
# Save (commit) the changes
connection.commit()
Attention
Par dĂ©faut, la connexion nâest pas en autocommit
, il faut committer explicitement les ordres SQL via lâappel Ă la mĂ©thode commit
.
Avertissement
Vos requĂȘtes SQL utilisent souvent les valeurs de variables. Vous ne devez pas assembler votre requĂȘte Ă lâaide dâopĂ©rations sur les chaĂźnes de caractĂšres, car cela nâest pas sĂ»r et rend votre programme vulnĂ©rable Ă une attaque par injection SQL.
# Never do this -- insecure!
symbol = 'RHAT'
cursor.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)
à la place, nous allons utiliser la capacité de substitution des paramÚtres. Placez un ?
comme indicateur partout oĂč vous voulez utiliser une valeur, puis fournissez un tuple de valeurs comme second argument de la mĂ©thode execute()
.
values = ('RHAT',)
cursor.execute('SELECT * FROM stocks WHERE symbol=?', values)
# Larger example that inserts many records at a time
purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
('2006-04-05', 'BUY', 'MSFT', 1000, 72.00),
('2006-04-06', 'SELL', 'IBM', 500, 53.00),
]
cursor.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)
Pour récupérer des données aprÚs avoir exécuté une instruction SELECT
, vous pouvez considérer le curseur comme un itérateur, appeler la méthode du curseur fetchone()
pour récupérer une seule ligne correspondante ou appeler fetchall()
pour obtenir une liste des lignes correspondantes.
cursor.execute('SELECT * FROM stocks WHERE symbol=?', ('RHAT',))
print(cursor.fetchone())
cursor.execute('SELECT * FROM stocks ORDER BY price')
print(cursor.fetchall())
for row in cusror.execute('SELECT * FROM stocks ORDER BY price'):
print(row)
Pour en savoir plus direction la documentation sqlite3
Le module logging
#
La journalisation (logging en anglais) est une façon de suivre les Ă©vĂ©nements qui ont lieu durant le fonctionnement dâun logiciel. Le dĂ©veloppeur du logiciel ajoute des appels Ă lâoutil de journalisation dans son code pour indiquer que certains Ă©vĂ©nements ont eu lieu.
Un Ă©vĂ©nement est dĂ©crit par un message descriptif, qui peut Ă©ventuellement contenir des donnĂ©es variables (câest-Ă -dire qui peuvent ĂȘtre diffĂ©rentes pour chaque occurrence de lâĂ©vĂ©nement). Un Ă©vĂ©nement a aussi une importance que le dĂ©veloppeur lui attribue ; cette importance peut aussi ĂȘtre appelĂ©e niveau ou sĂ©vĂ©ritĂ©.
Quand utiliser logging ?
Le module logging
fournit un ensemble de fonctions debug()
, info()
, warning()
, error()
et critical()
. Pour plus dâinformation voir la documentation du module logging.
Pour déterminer quand employer quel niveau référez-vous au tableau suivant:
TĂąche que vous souhaitez mener |
Le meilleur outil pour cette tĂąche |
---|---|
Sortie console dâun script |
|
Rapporter des Ă©vĂšnements qui ont lieu au cours du fonctionnement normal dâun programme |
|
Ămettre un avertissement (warning en anglais) |
|
Rapporter une erreur sans lever dâexception |
|
Les fonctions de journalisation sont nommĂ©es dâaprĂšs le niveau ou la sĂ©vĂ©ritĂ© des Ă©vĂšnements quâelles suivent. Les niveaux standard et leurs applications sont dĂ©crits ci-dessous (par ordre croissant de sĂ©vĂ©ritĂ©) :
Niveau |
Quand il est utilisé |
---|---|
DEBUG |
Information dĂ©taillĂ©e, intĂ©ressante seulement lorsquâon diagnostique un problĂšme. |
INFO |
Confirmation que tout fonctionne comme prévu. |
WARNING |
Quelque chose dâinattendu a eu lieu le logiciel fonctionne encore normalement. |
ERROR |
Un problĂšme plus sĂ©rieux, le logiciel nâa pas Ă©tĂ© capable de rĂ©aliser une tĂąche. |
CRITICAL |
Une erreur sĂ©rieuse, indiquant que le programme lui-mĂȘme pourrait ĂȘtre incapable de continuer Ă fonctionner. |
Note
Le niveau par défaut est WARNING
, ce qui signifie que seuls les évÚnements de ce niveau et au-dessus sont suivis, sauf si le paquet logging est configuré pour faire autrement.
Les Ă©vĂšnements suivis peuvent ĂȘtre gĂ©rĂ©s de diffĂ©rentes façons. La maniĂšre la plus simple est de les afficher dans la console. Une autre mĂ©thode commune est de les Ă©crire dans un fichier.
import logging
logging.warning('Watch out!') # will print a message to the console
logging.info('I told you so') # will not print anything
Il est trĂšs commun dâenregistrer les Ă©vĂšnements dans un fichier:
import logging
logging.basicConfig(filename='example.log',level=logging.DEBUG)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
Attention
Lâappel Ă basicConfig()
doit ĂȘtre fait avant un appel Ă debug()
, info()
, etc. Comme lâobjectif est dâavoir un outil de configuration simple et dâusage unique, seul le premier appel aura un effet, les appels suivants ne font rien.
Indication
Si votre programme est composĂ© de plusieurs modules, voici une façon dâorganiser lâoutil de journalisation :
import logging
import mylib
def main():
logging.basicConfig(filename='myapp.log', level=logging.INFO)
logging.info('Started')
mylib.do_something()
logging.info('Finished')
if __name__ == '__main__':
main()
import logging
def do_something():
logging.info('Doing something')
Pour changer le format utilisé pour afficher le message, vous devez préciser le format que vous souhaitez employer :
import logging
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
logging.basicConfig(format='%(asctime)s %(message)s')