Python est un langage de programmation, sous licence libre, orienté objet, multi-paradigme et multiplateformes.
Python est à la fois à typage dynamique (il n’utilise pas de déclaration de type explicite) et fortement typé (une fois qu’une variable a un type, cela a une importance).
Les programmes Python sont des scripts donc des fichiers textes.
Les blocs de code (fonctions, instructions if
, boucles for
ou while
etc.) sont définis par leur indentation. L’indentation démarre le bloc et la désindendation le termine. Il n’y a pas d’accolades, de crochets ou de mots clés spécifiques.
Python utilise le retour chariot pour séparer les instructions, deux points (:
) et l’indentation pour séparer les blocs de code.
#!/usr/bin/python
# coding: utf-8
# un programme python
print("Quelle est votre langue ? ")
langue = raw_input()
if langue == "fr" :
message = "Bonjour le monde"
else :
message = "Hello world"
# voir aussi : if ... elif ... else
print("Donnez un nombre : ")
nb = input()
i = 0
while i < nb:
#print message
print message, i + 1, " fois"
i += 1
Dans un script Python :
#!
(le shebang) est indiqué sur la première ligne.# coding: utf-8
Il existe plusieurs manières d’exécuter un script Python :
$ chmod +x ex-helloworld.py ; ./ex-helloworld.py
$ python ex-helloworld.py
ou $ python3 ex-helloworld.py
La documentation du langage Python :
Vous pouvez aussi obtenir facilement des informations sur tout objet, module ou fonction en utilisant l’interpréteur Python avec les fonctions dir(object)
, help(object)
ou encore les docstrings avec l’attribut __doc__
.
Par exemple pour le type str
:
# code pour obtenir des informations sur les string :
# dir([object]) retourne la liste des attributs de l'objet object :
print dir(str)
# help([object]) invoque le système d'aide intégré :
help(str)
# visualiser les docstrings en appelant le paramètre __doc__ sur un objet :
print str.__doc__
Les types de base en Python sont relativement complets et puissants, il y a entre autres :
int
est un entier illimité. Avant la version 3.0, ce type était dénommé long
, et le type int
correspondait à un entier 32 ou 64 bits. Néanmoins, une conversion automatique évitait tout débordement.float
est un flottant équivalent au type double du Ccomplex
est une approximation d’un nombre complexe (typiquement deux float
).tuple
sont des listes non modifiables d’objets hétérogènes. Les objets list
sont des tableaux dynamiques (ils étendent automatiquement leur taille lorsque nécessaire) et acceptent des types de données hétérogènes. Les objets set
sont des ensembles non ordonnés d’objets. Les objets frozenset
forment une variante non modifiable des set. Les objets dict
sont des tableaux associatifs (ou dictionnaires) permettant d’associer un objet (une clé) à un autre (une valeur). Les objets str
sont des chaînes de caractères. Les chaines d’octets sont des objets bytes. Les objets str et bytes sont non modifiables. Les objets bytearray
sont des chaînes d’octets modifiables.En Python, on distingue deux types d’objets : les mutables (listes, dictionnaires, sets, …) et les non mutables (str, int, float, tuples, …).
Les mutables sont ceux qu’on peut modifier après leur création. Les non mutables (immuable) sont ceux qu’on ne peut pas modifier après création.
Les objets itérables sont parcourus à l’aide d’une boucle for
de la manière suivante :
for element in objet_iterable:
traiter(element)
Il est possible de dériver les classes des types de base pour créer ses propres types.
En Python, les variables ne sont jamais explicitement typées. En se basant sur la valeur que vous lui assignez, Python gère les types de données en interne.
Pour connaître le type d’une variable, il suffit d’utiliser la fonction interne à Python type()
. Pour transtyper (cast) une variable, on préfixe les parenthèses avec le type désiré.
#!/usr/bin/python
# Python 2
t = "Hello"
i = 0
nb = raw_input()
# transtypage :
a = int(nb)
# connaître le type d'une variable :
print type(t) # <type 'str'>
print type(i) # <type 'int'>
print type(nb) # <type 'str'>
print type(a) # <type 'int'>
# affichage
print "i = %d" % i # i = 0
On utilisera suivant les versions de Python :
input()
retourne une chaîne comme raw_input()
en Python 2input()
est équivalent à eval(raw_input())
input(prompt)
et raw_input(prompt)
peuvent recevoir en argument une invite (prompt).
Pour lire plusieurs choses sur la même ligne :
print "Saisir un pays et une ville : "
mots = raw_input().split(" ")
pays = mots[0]
ville = mots[1]
print("Vous habitez à {} ({})".format(ville, pays))
print "Saisir un pays et une ville : "
pays, ville = raw_input().split(" ")
print("Vous habitez à {} ({})".format(ville, pays))
print "Saisir une longueur et une largeur : "
mots = raw_input("-> ").split(" ")
longueur = int(mots[0])
largeur = int(mots[1])
print(longueur * largeur)
print "Saisir une longueur et une largeur : "
longueur, largeur = map(int, raw_input("-> ").split(" "))
print(longueur * largeur)
On utilisera print
:
# coding: utf-8
# affiche une chaîne de caractères
print("Hello world !")
s = "Hello world !"
print(s)
print(s + s) # concaténation
# affiche des valeurs
print(1)
i = 1
print(i)
f = 0.5
print('i = %d et f = %.1f' % (i, f))
# avec un formatage :
print('{0:5d}'.format(i))
print(repr(i).rjust(5))
print(repr(i).zfill(5))
# En Python3 :
print('.', end='') # pour désactiver le saut de ligne par défaut de print
Ou write
du module sys
:
import sys
sys.stdout.write('.') # il n'y aura pas de saut de ligne automatique ici
Ceci est important et il ne fait aucun mal de le souligner : en Python tout est objet. Les chaînes sont des objets. Les listes sont des objets. Les fonctions sont des objets. Même les modules sont des objets.
Appeler des méthodes d’une classe :
# coding: utf-8
print "Saisir un message : "
message = raw_input()
print message.upper()
print message.lower()
print len(message)
# attention les chaînes ne sont pas modifiables même avec l'opérateur []
# message[0] = 'X
# il faut créer une nouvelle chaîne
message = 'X' + message[1:]
print message
Voir aussi : find()
, replace()
, split()
, …
Les listes sont de simples suites d’éléments indexés. Dans les listes, les éléments qui se suivent ne sont pas nécessairement de même type.
Il existe deux façons de déclarer une liste :
# coding: utf-8
# Déclaration de listes
# soit en créant une liste d'emblée, vide ou non :
liste1 = []
liste2 = [1,2,3,4,5]
print type(liste1) # <type 'list'>
print type(liste2) # <type 'list'>
# soit en typant la variable :
liste3 = list()
print type(liste3) # <type 'list'>
# Utilisation des listes
print "Longueur de la liste liste2 : "
print len(liste2) # 5
print "Les éléments de la liste liste2 : "
for element in liste2:
print(element)
print "Quelques éléments de la liste liste2 : "
for n in range(0,5,2):
print liste2[n]
# modification d'un élément
liste2[0] = 0
print "Les éléments de la liste liste2 : "
print liste2 # [0, 2, 3, 4, 5]
# suppression d'éléments
del liste2[1]
liste2.remove(3)
print "Les éléments restants de la liste liste2 : "
print liste2 # [0, 4, 5]
liste3.append(1);
liste3.append("un");
print "Les éléments de la liste liste3 : "
print liste3 # [1, 'un']
liste1.append(3);
liste1.append(2);
liste1.append(1);
print "Les éléments de la liste liste1 : "
print liste1 # [3, 2, 1]
liste1.sort() # voir aussi : reverse()
print "Les éléments triés de la liste liste1 : "
print liste1 # [1, 2, 3]
Voir aussi : count()
, index()
, …
Les liste possèdent des méthodes leur permettant de se comporter comme des piles :
pile = [0,1,2,3,4,5]
pile.append(6);
print "Longueur de la pile : "
print len(pile) # 7
print "Élément de la pile : "
print pile.pop() # 6
print "Longueur de la pile : "
print len(pile) # 6
# ...
Un tuple est une liste qui ne peut plus être modifiée.
# coding: utf-8
# Déclaration des tuples
# soit en créant une tuple d'emblée, vide ou non :
tuple1 = ()
tuple2 = (1,2,3,4,5)
print type(tuple1) # <type 'tuple'>
print type(tuple2)
# soit en typant la variable :
tuple3 = tuple()
tuple3 = (1,) # ne pas oublier la virgule
tuple3 = 1,2,3 # les parenthèses ne sont pas obligatoires
print type(tuple3)
print(tuple3)
# Utilisation des tuples
print "Longueur de tuple2 : "
print len(tuple2) # 5
print "Les éléments de tuple2 : "
for element in tuple2:
print(element)
print "Quelques éléments de tuple2 : "
for n in range(0,5,2):
print tuple2[n]
Les tuples et Python permettent de réaliser des assignations multiples :
x, y = (1, 2)
print x, y # 1 2
x, y = y, x
print x, y # 2 1
Structures de données fondamentales en Python, les objets dict
sont des tableaux associatifs (ou dictionnaires) permettant d’associer un objet (une clef) à un autre (une valeur), le tout embrassé par des accolades { }. La clé est la valeur sont associées par un “:” et les membres se suivent, séparés par des virgules comme dans des listes.
L’utilisation d’un dictionnaire est en particulier utile lorsque les clés sont des mots qui permettent ainsi d’avoir une approche sémantique des données.
# coding: utf-8
# Déclaration des dictionnaires
dictionnaire1 = {}
dictionnaire2 = {'nom':'Descartes','prenom':'René'}
dictionnaire3 = dict()
print type(dictionnaire1) # <type 'dict'>
print type(dictionnaire2)
print type(dictionnaire3)
print "Les clés : "
for cle in dictionnaire2.keys():
print cle
print "Les valeurs : "
for valeur in dictionnaire2.values():
print valeur
print "Les clés/valeurs : "
for cle,valeur in dictionnaire2.items():
print cle, valeur
# ajout
dictionnaire1['nom'] = 'Pascal'
dictionnaire1['prenom'] = 'Blaise'
print "Les clés/valeurs : "
for cle,valeur in dictionnaire1.items():
print cle, valeur
dictionnaire1.clear()
print "Les clés/valeurs : "
for cle,valeur in dictionnaire1.items():
print cle, valeur
Voir aussi : get()
, has_key()
, …
En plus des collections précédentes (tuple
, list
, set
, dict
, bytearray
, …), Python propose un module collections
avec d’autres objets conteneurs.
Documentations :
namedtuple()
, deque
, Counter
, OrderedDict
, defaultdict
namedtuple()
, deque
, Counter
, OrderedDict
, defaultdict
, ChainMap
, UserDict
, UserList
et UserString
Exemple :
import collections
d1 = collections.OrderedDict()
# ou pour OrderedDict par exemple :
from collections import OrderedDict
d2 = OrderedDict()
OrderedDict
: des dictionnaires qui conservent l’ordre d’insertionimport collections
#from collections import OrderedDict
d = collections.OrderedDict()
d['c'] = 1
d['b'] = 2
d['a'] = 3
# conserve l'ordre d'insertions
print(d.keys()) # ['c', 'b', 'a']
Counter
: un dictionnaire spécialisé pour le comptageimport collections
#from collections import Counter
c = collections.Counter()
print(c['roger']) # 0
c['roger'] += 1
print(c['roger']) # 1
for i in range(0,5):
c['robert'] += 1
print(c['robert']) # 0 1 2 3 4 5
print(c) # Counter({'robert': 5, 'roger': 1})
# compte les occurences
print(collections.Counter('le soleil brille')) # Counter({'l': 5, 'e': 3, ' ': 2, 'i': 2, 'b': 1, 'o': 1, 's': 1, 'r': 1})
namedtuple
: des tuples nommés et structurés#from collections import namedtuple
Fiche = collections.namedtuple("Fiche", "nom prenom age")
f = Fiche(nom="Dupond", prenom="robert", age=66)
print(f) # Fiche(nom='Dupond', prenom='robert', age=66)
# toujours itérable :
for c in f:
print c # Dupond robert 66
print(f.nom) # Dupond
deque
: des listes à double entrée, les objets de la liste peuvent ainsi être ajoutés ou retirés, soit à gauche soit à droite, et en temps constant#from collections import deque
d = collections.deque('ell')
for elem in d:
print(elem.upper()) # E L L
d.append('o')
d.appendleft('h')
print(d) # deque(['h', 'e', 'l', 'l', 'o'])
d.pop()
print(d) # deque(['h', 'e', 'l', 'l'])
print(collections.deque(reversed(d))) # deque(['l', 'l', 'e', 'h'])
Si créer des instances est simple, les détruire est encore plus simple. En général, il n’y a pas besoin de libérer explicitement les instances, elles sont libérées automatiquement lorsque les variables auxquelles elles sont assignées sont hors de portée. Sinon, le mot-clé del
sert à supprimer explicitement une instance.
La technique du ramasse-miettes (garbage collector) Python est le « comptage de références » et lorsque ce compteur descend alors à 0, Python détruit l’instance automatiquement. En général, vous pouvez simplement ignorer la gestion mémoire et laisser Python nettoyer derrière vous car les fuites mémoire sont rares avec ce langage.
Python permet la programmation procédurale.
Python dispose de fonctions comme la plupart des autre langages, mais il n’a pas de fichiers d’en-tête séparés comme C++.
Lorsque vous avez besoin d’une fonction, vous n’avez qu’à la déclarer et l’écrire.
def foo(n):
Le mot clé def
débute une déclaration de fonction, suivi du nom de la fonction, puis des arguments entre parenthèses. Les arguments multiples (non montré ici) sont séparés par des virgules.
Les fonctions Python ne définissent pas le type de leur valeur de retour, elle ne spécifient même pas si elle retournent une valeur ou pas. En fait chaque fonction Python retournera une valeur, si la fonction exécute une instruction return
, elle va en retourner la valeur, sinon elle retournera None
, la valeur nulle en Python.
Les arguments ne spécifient pas de types de données. En Python, les variables ne sont jamais explicitement typées. En se basant sur la valeur que vous lui assignez, Python gère les types de données en interne.
Vous pouvez documenter une fonction Python en lui donnant une chaîne de documentation (doc string
).
def foo(n):
"""Je suis une fonction qui reçoit un paramètre n.
Je retourne un string."""
print foo.__doc__
Les tripes guillemets indiquent une chaîne multi-lignes.
Une doc string
, si elle existe, doit être la première chose déclarée dans une fonction (la première chose après les deux points). Techniquement parlant, vous n’êtes pas obligés de donner une doc string
à votre fonction, mais vous devriez toujours le faire.
Une fonction, comme tout le reste en Python, est un objet.
Qu’est-ce qu’un objet ? Chaque langage de programmation définit le terme «objet» à sa manière. En Python, tout est objet dans le sens où tout peut être assigné à une variable ou passé comme argument à une fonction.
Les fonctions Python n’ont pas de begin ou end explicites, ni d’accolades qui pourraient marquer là ou commence et ou se termine le code de la fonction. Le seul délimiteur est les deux points (:
) et l’indentation du code lui-même.
#!/usr/bin/python
# coding: utf-8
def reponse(x):
"""Affiche la réponse x"""
print "La réponse est", x
t = "Hello"
i = 0
reponse(t) # La réponse est Hello
reponse(i) # La réponse est 0
def ratio(numerateur, denominateur=1):
"""Retourne le ratio n/d"""
return numerateur/denominateur
print ratio(1, 2) # 0
print ratio(1., 2.) # 0.5
print ratio(5) # 5
Remarque : Comme tout langage à typage dynamique, il n’est pas possible d’effectuer une surchage de fonctions (ou de méthodes). Voir : Comment effectuer une surcharge ?
Python autorise les paramétres par défaut pour les fonctions :
def foo(a=2):
print a
foo() # affiche 2
foo(12) # affiche 12
foo(a=12) # affiche 12
foo() # affiche 2
def bar(a=[]):
print a
bar() # affiche []
bar([1,2,3,4]) # affiche [1, 2, 3, 4]
bar() # affiche []
Attention, le paramètre par défaut est construit une fois pour toute quand la fonction est générée. Cela peut provoquer des effets de bord lorsque le paramètre est mutable :
import random
def stuff(a=[]):
a.append(random.randint(0,9))
return a
print stuff() # affiche [0]
print stuff() # affiche [0, 8]
print stuff() # affiche [0, 8, 8]
print stuff() # affiche [0, 8, 8, 7]
print stuff([]) # affiche [9]
print stuff([5,1]) # affiche [5, 1, 6]
print stuff() # affiche [0, 8, 8, 7, 1]
En fait, une variable est un nom (un label, un identifiant) pointant vers une référence d’un objet.
a = 1
a = 2
Attention, a
n’est pas un emplacement mémoire qui stocke la valeur 1 puis la valeur 2. En Python, a
est une référence à un objet avec la valeur 1, puis est réaffecté en tant que référence à un objet avec la valeur 2 :
a = 2
print "Référence de a : %d" % id(a) # Référence de a : 33956160
a = 1
print "Référence de a : %d" % id(a) # Référence de a : 33956184
b = a
print "Référence de b : %d" % id(b) # Référence de b : 33956184
b = 3
print "Référence de b : %d" % id(b) # Référence de b : 33956136
Lorsqu’on a affecté a
à b
, on a copié la valeur de la référence de a
dans b
(à ce moment là, a
et b
ont la même référence). Ici, les valeurs 1
, 2
et 3
sont des « objets » différents et les références ne sont donc pas les mêmes.
Idem pour une liste :
liste1 = [1, 2, 3]
print "Référence de liste1 : %d" % id(liste1) # Référence de liste1 : 140042289226384
liste2 = liste1
print "Référence de liste2 : %d" % id(liste2) # Référence de liste2 : 140042289226384
liste2.append(4)
print(liste2) # [1, 2, 3, 4]
print(liste1) # [1, 2, 3, 4]
print "Référence de liste1 : %d" % id(liste1) # Référence de liste1 : 140042289226384
print "Référence de liste2 : %d" % id(liste2) # Référence de liste2 : 140042289226384
print liste1 is liste2 # True
Mais ici, liste1
et liste2
ont la même référence car il n’y a qu’un seul objet (mais deux identifiants liste1
et liste2
qui ont la même valeur de référence).
C’est ce mécanisme qui est utilisé quand on passe des arguments à une fonction : Il y un passage de références (par valeur) des paramètres de la fonction. C’est la valeur de la référence qui est copiée.
def ajouter(l, a):
print "Référence de liste : %d" % id(liste) # Référence de liste : 140660673366712
l.append(a)
liste = [1,2,3,4]
print "Référence de liste : %d" % id(liste) # Référence de liste : 140660673366712
print liste # [1, 2, 3, 4]
ajouter(liste,5)
print liste # [1, 2, 3, 4, 5]
print "Référence de liste : %d" % id(liste) # Référence de liste : 140660673366712
Évidemment, cela dépendra si l’objet passé en argument est mutable ou non.
Python permet la gestion des exceptions afin de faciliter la mise en oeuvre de code robuste.
Lire : les exceptions en Python2 ou en Python3.
Une exception est l’interruption de l’exécution du programme à la suite d’un événement particulier (c’est-à-dire exceptionnel !) et le transfert du contrôle à des fonctions spéciales appelées gestionnaires.
def ratio(num, den):
return num/den
print ratio(1., 2.) # affiche 0.5
# le programme s'arrête et lève une exception :
print ratio(1, 0) # lève une exception ZeroDivisionError
print ratio("1", "2") # lève une exception TypeError
print ratio(1., i) # lève une exception NameError
La gestion d’une exception est découpée en plusieurs parties distinctes :
raise
(lance ou lève une exception)try
et except
finally
(un bloc qui est exécuté après que tous les autres blocs aient été exécutés) et else
(bloc exécuté si aucune exception n’est levée).Forme minimaliste :
try:
# instructions pouvant provoquer une exception
except: # attrape toutes les exceptions
# instruction(s) exécutée(s) en cas d'exception
Forme complète :
try:
# instructions pouvant provoquer une exception
except: # attrape toutes les exceptions
# instruction(s) exécutée(s) en cas d'exception
else:
# instruction(s) exécutée(s) si aucune exception n'est levée
finally:
# instruction(s) toujours exécutée(s) à la fin
Il est possible et conseillé de préciser le type d’exception après le mot clé except
:
ingredients = ['lait', 'farine', 'sucre', 'sel']
try:
# si i est plus grand que la taille du tableau
i = 4
ingredient = ingredients[i]
except IndexError:
ingredient = None
print ingredient # affiche None
Ou d’en indiquer plusieurs :
ingredients = ['lait', 'farine', 'sucre', 'sel']
try:
# si i n'est pas un type entier
i = "0"
ingredient = ingredients[i]
except (IndexError,TypeError):
ingredient = None
print ingredient # affiche None
Lever une exception :
def truc(a):
if a == 0 :
raise ValueError("a ne peut être égal à zéro")
print a
try:
truc(1)
truc(-1)
truc(0) # lève une exception ValueError
except ValueError as e:
print e # a ne peut être égal à zéro
On peut aussi relancer une exception :
def ratio(num, den):
try:
if den == 0:
raise ZeroDivisionError("Le dénominateur ne peut être égal à zéro")
except ZeroDivisionError:
raise # on relance l'exception
else:
return num/den
try:
print ratio(1., 2.) # affiche 0.5
print ratio(1, 0) # lève l'exception ZeroDivisionError
except Exception as e:
print(e) # affiche "Le dénominateur ne peut être égal à zéro"
Remarque : il est possible de créer ses propres (classes d’) exceptions en héritant de la classe Exception
.
Les assertions sont un moyen simple de s’assurer, avant de continuer, qu’une condition est respectée. On utilise le mot clé assert
: assert condition
si condition
est égale à True
, l’exécution se poursuit normalement sinon, une exception AssertionError
est levée :
#!/usr/bin/python
# coding: utf-8
def ratio(num, den):
try:
assert den != 0
except AssertionError:
return None
else:
return num/den
print ratio(1., 2.) # affiche 0.5
print ratio(1, 0) # affiche None
Une classe se définit avec le mot-clé class
.
Attention : Python oblige de déclarer l’instance de l’objet courant, conventionnellement nommée self
, comme premier argument des méthodes, et à chaque fois que l’on souhaite accéder à une donnée de cette instance dans le corps de cette méthode.
La méthode __init__
permet d’initialiser une instance, elle est appelé automatiquement lorsqu’un objet a été créé. Il existe aussi __new__
qui est appelé avant la création de l’objet.
class Vehicule:
"""La classe Vehicule"""
# un attribut
couleur = ""
# des méthodes
def __init__(self, couleur="blanche"):
self.couleur = couleur
def avance(self):
"""La méthode avance()"""
print "j'avance"
def tourne(self):
"""La méthode tourne()"""
print "je tourne"
# une fonction spéciale
def __repr__(self):
""" L'affichage de l'objet dans l'interpréteur """
return "Vehicule(couleur=\'" + self.couleur + "\')"
v1 = Vehicule()
v1.avance() # j'avance
# affiche le nom de la classe :
print v1.__class__.__name__ # Vehicule
# et son type :
print type(v1) # <type 'instance'>
print v1 # Vehicule(couleur='blanche')
Remarque : Le langage Python a un support très limité de l’encapsulation. Il n’y a pas, comme en Java ou C++ par exemple, de contrôle de l’accessibilité par des mots clefs comme protected
ou private
.
Les variables d’instance “privées” (private
) auxquelles on ne peut accéder qu’à l’intérieur d’un objet n’existent donc pas en Python. Cependant, il existe une convention en Python :
_b
) doit être traité comme un membre non publique (qu’il s’agisse d’une fonction, d’une méthode ou d’un attribut).__c
) sera textuellement remplacé par _classname__c
, où classname
est le nom de classe actuel (pour éviter les conflits de noms avec ceux définis par des sous-classes). Ceci fait que l’accès monObjet.__c
provoquera une exception de type AttributeError
et pourrait faire croire à une encapsulation privée ce qui n’est pas le cas).Remarque : Le slogan des développeurs Python est « we’re all consenting adults here » (nous sommes entre adultes consentants) et qu’une simple convention suffira pour préciser les responsabilités (Source : fr.wikipedia.org).
Exemple :
class MaClasse:
def __init__(self):
# trois attributs :
self.a = 1
self._b = 2
self.__c = 3
monObjet = MaClasse()
# affiche les attributs d'un instance :
print(vars(monObjet)) # {'a': 1, '_MaClasse__c': 3, '_b': 2}
# donc :
print(monObjet.a) # {'a': 1, '_MaClasse__c': 3, '_b': 2}
print(monObjet._b) # {'a': 1, '_MaClasse__c': 3, '_b': 2}
print(monObjet._MaClasse__c) # {'a': 1, '_MaClasse__c': 3, '_b': 2}
# mais :
print(monObjet.__c) # AttributeError: MaClasse instance has no attribute '__c'
Ensuite, le mécanisme des propriétés (property
) permettra d’implémenter des accesseurs/mutateurs (getter/setter) : Manipuler les attributs.
Python reconnaît trois types de méthodes :
@classmethod
.@staticmethod
.Remarque : Comme tout langage à typage dynamique, il n’est pas possible d’effectuer une surchage de fonctions ou de méthodes. Voir : Comment effectuer une surcharge ?
Python fournit un mécanisme pour définir un ensemble pré-défini d’opérateurs : tout objet Python peut se voir doté de méthodes dites spéciales.
Ces méthodes, commençant et finissant par deux tirets de soulignement (underscores), sont appelées lors de l’utilisation d’un opérateur sur l’objet : + (méthode __add__
), += (méthode __iadd__
), [] (méthode __getitem__
), () (méthode __call__
), etc. Des méthodes comme __repr__
et __str__
permettent de définir la représentation d’un objet dans l’interpréteur interactif et son rendu avec la fonction print
. Il existe aussi : __new__
et __del__
.
class Temps:
def __init__(self, heure=0, minute=0, seconde=0):
self.valeur = (heure*3600)+(minute*60)+seconde
def __add__(self, a):
temps = Temps()
if type(a) == int:
temps.valeur = self.valeur + a
elif isinstance(a, Temps):
temps.valeur = self.valeur + a.valeur
else: raise AttributeError, "aucun traitement pour le type " + str(type(a))
return temps
def __radd__(self, o):
return self + o
def __str__(self):
return "{0:02}:{1:02}:{2:02}".format((self.valeur/3600), (self.valeur%3600)/60, (self.valeur%60))
t1 = Temps()
print("t1 = %s" % t1) # t1 = 00:00:00
t2 = Temps(1, 60, 30)
print("t2 = %s" % t2) # t2 = 02:00:30
# appel __add__ :
t1 = t2 + 10
print("t1 = %s" % t1) # t1 = 02:00:40
# appel _radd__ :
t1 = 20 + t2
print("t1 = %s" % t1) # t1 = 02:00:50
t1 = t1 + t2
print("t1 = %s" % t1) # t1 = 04:01:20
Python supporte l’héritage (et l’héritage multiple).
class Voiture(Vehicule):
"""La classe Voiture"""
def __init__(self, couleur="", model=""):
Vehicule.__init__(self, couleur)
# attributs
self.model = model
def afficherModel(self):
print self.model
def tourne(self):
Vehicule.tourne(self)
print "mais en douceur !"
v2 = Voiture("rouge", "306")
v2.afficherModel() # 306
v2.avance() # j'avance
v2.tourne() # je tourne mais en douceur !
# il faudrait redéfinir __repr__
print v2 # Vehicule(couleur='rouge')
setattr(v2, "model", "206")
print getattr(v2, "model")
v2.afficherModel() # 206
v3 = Voiture()
# il faudrait redéfinir __repr__
print v3 # Vehicule(couleur='')
Il existe plusieurs techniques pour manipuler les attibuts autrement que directement :
v2.model = "406"
print(v2.model) # 406
v2.afficherModel() # 406
Il est possible de lire ou de modifier un attribut dynamiquement avec les fonctions getattr()
et setattr()
.
v2 = Voiture("rouge", "306")
setattr(v2, "model", "206")
print getattr(v2, "model") # 206
v2.afficherModel() # 206
Il est aussi possible de passer par des getter (accesseur) et des setter (mutateurs). Il faut que la classe hérite de object
et que l’attribut soit préfixé par un underscore ou encore mieux deux underscore.
Il y a deux écriture possibles :
property
@property
Exemple de getter (accesseur) et des setter (mutateur) :
# Version 1
class Personne(object):
def __init__(self, nom=""):
# un atribut pseudo privé :
self.__nom = nom
@property
def nom(self):
print "accesseur de nom"
return self.__nom
@nom.setter
def nom(self, nom):
print "mutateur de nom"
self.__nom = nom
@nom.deleter
def nom(self):
del self.__nom
p = Personne("Dupond")
# appel mutateur (setter) :
p.nom = "Durand"
# appel accesseur (getter) :
print(p.nom)
# ou :
# Version 2
class Personne(object):
def __init__(self, nom=""):
# un atribut pseudo privé :
self.__nom = nom
def getNom(self):
print "accesseur de nom"
return self.__nom
def setNom(self, nom):
print "mutateur de nom"
self.__nom = nom
def delNom(self):
del self.__nom
#nom = property(getNom, setNom)
nom = property(getNom, setNom, delNom, "Je suis la propriété nom.")
p = Personne("Dupond")
# appel mutateur (setter) :
p.nom = "Durand"
# appel accesseur (getter) :
print(p.nom)
Python permet la programmation modulaire.
Les modules sous Python sont des fichiers (.py
) qui regroupent des ensembles de fonctions et/ou de classes.
Pour utiliser des modules dans un programme, il faut utiliser l’instructions import
:
import math
print math.sqrt(4)
# ou en créant un alias :
import math as m
print m.sqrt(4) # 2.0
On peut aussi utiliser from
mais cela est déconseillé pour des risques de conflits de noms :
from math import *
print sqrt(4) # 2.0
Il existe de nombreux modules standards dont : cgi
, math
, os
, pickle
, random
, re
, socket
, sys
, time
, urllib
, …
Il est évidemment possible de créer ses propres modules. Par exemple, un fichier fonctions.py
qui contient les fonctions reponse
et ratio
vues précédemment.
Pour cela, il faut :
.py
situé dans le même dossier que le fichier qui l’importe. Donc :import fonctions
print fonctions.ratio(1.,2.) # 0.5
Dans ce cas, Il faudra :
__init__.py
qui assurera l’importation de tous les fichiers que le répertoire contient :from fonctions import *
Puis, on importe le module lib
(qui est le nom du répertoire qui contient le fichier fonctions.py
) :
import lib
print lib.ratio(1.,2.) # 0.5
import sys
sys.path.append("monchemin")
import fonctions
print fonctions.ratio(1.,2.) # 0.5
Il est donc possible de regrouper des modules dans des packages. Comme pour d’autres langages, un package est tout simplement un répertoire. Ce répertoire pourra contenir d’autres répertoires (des packages) et des fichiers (des modules).
Remarque : Lors de l’importation d’un module, le programme va tout d’abord vérifier si le module à importer se trouve dans le dictionnaire sys.modules
(module de base + les modules d’autres bibliothèques que vous avez installées). Si le module n’est pas trouvé, le programme le cherchera à partir de la liste définie par sys.path
(qui contient le répertoire courant, la variable d’environnement PYTHONPATH
entre autres).
Au moment d’importer le module, Python va lire (ou créer si il n’existe pas) un fichier .pyc
(à partir de la version 3.2, ce fichier se trouve dans un dossier __pycache__
). Ce fichier est généré par Python et contient du code compilé du module.
Si vous voulez ajouter du code au sein d’un module pour le tester par exemple, il sera utile de procéder ainsi :
#!/usr/bin/python
# coding: utf-8
def reponse(x):
"""Affiche la réponse x"""
print "La réponse est", x
def ratio(numerateur, denominateur=1):
"""Retourne le ratio n/d"""
return numerateur/denominateur
if __name__ == "__main__":
print ratio(1., 2.) # 0.5
Les modules sont des objets et tous les modules disposent de l’attribut prédéfini __name__
. Le __name__
d’un module dépend de la façon dont vous l’utilisez. Si vous importez le module, son __name__
est le nom de fichier du module sans le chemin d’accès ni le suffixe. Mais vous pouvez aussi lancer le module directement en tant que programme, dans ce cas __name__
va prendre par défaut une valeur spéciale __main__
.
Python possède plusieurs modules disponibles pour la création de logiciels avec une interface graphique. Le plus répandu est Tkinter. Ce module convient à beaucoup d’applications et peut être considéré comme suffisant dans la plupart des cas. Néanmoins, d’autres modules ont été créés pour pouvoir lier Python à d’autres bibliothèques logicielles (« toolkit ») : wxPython pour wxWidgets, PyQt pour Qt, …
Installer Tkinter :
sudo apt-get install python-tk python-imaging-tk
Exemple :
# -*- coding: utf-8 -*-
# on commence toujours par importer le module tkinter
# ici on lui donne le surnom (alias) de tk
# pour python3.x Tkinter devient tkinter
import Tkinter as tk
# il suffit alors de déclarer l'objet Tk()
# qui deviendra la fenêtre principale
fenetre = tk.Tk()
fenetre.title('Test Tkinter')
# on crée ensuite un objet Label()
# rattaché à fenetre
# pour afficher du texte non éditable
# on profite du constructeur de l'objet
# pour définir un texte "Hello World"
# dans la foulée (on peut faire autrement)
texte = tk.Label ( fenetre, text="Hello World" )
# l'objet Label() nommé texte est ensuite
# rendu visible dans fenetre grâce à pack()
texte.pack()
# un bouton
bouton = tk.Button(fenetre)
bouton.config(text='Quitter', command=fenetre.destroy)
bouton.pack()
# pour finir, on lance la boucle programme
fenetre.mainloop()
# that's all, folks!
Pour lire le contenu d’un fichier, il faudra tout d’abord l’ouvrir (open()
) puis le lire (read()
qui retourne une chaîne de caractères ou readlines()
qui retourne une liste de chaînes de caractères) et pour finir le fermer (close()
) :
fichier = open('/etc/passwd','rb') # Ouverture du fichier en mode lecture
lignes = fichier.readlines() # Récupération du contenu du fichier
# Traitement ligne par ligne
for ligne in lignes:
sp = ligne.split('#')[0] # Élimination des commentaires potentiels
sp = sp.split(':') # Séparation
#print sp
print "Utilisateur : " + sp[0] + " - UID : " + sp[2]
fichier.close() # Fermeture du fichier
Voir aussi la méthode seek()
pour se déplacer dans un fichier.
Pour écrire dans un fichier, il suffit del’ouvrir (open()
) puis d’écrire (write()
pour une chaîne de caractères ou writelines()
pour une liste de chaînes de caractères) et pour finir le fermer (close()
) :
fichier = open('essai.txt','w') # Ouverture du fichier en mode écriture (avec écrasement)
fichier.write("hello world !") # Écriture d'un contenu dans le fichier
fichier.close() # Fermeture du fichier
Voir aussi le module pickle
pour enregistrer des objets dans des fichiers.
Remarque : les méthodes open()
et close()
ne sont pas obligatoires
fichier = file('essai.txt','r')
print fichier.read()
Pour récupérer la liste des fichiers d’un répertoire :
os.listdir(path)
retourne une liste contenant les noms de tous les fichiers et répertoires de pathglob.glob(path)
qui renvoie une liste contenant le chemin complet des fichiers ou répertoires contenus dans pathimport glob
import os.path
fichiers=[]
repertoire = glob.glob('./*')
for i in repertoire:
if os.path.isfile(i):
fichiers.append(i)
print fichiers
Voir aussi : os.path.getsize()
qui retourne la taille d’un fichier, os.remove()
pour supprimer , os.rename()
pour renommer , os.move()
pour déplacer, os.chdir()
pour changer de répertoire courant, … et le module ftplib
pour dialoguer avec un serveur FTP.
Pour exécuter une commande, on fera :
import os
os.system("ls");
Voir aussi : les foncions du module os
Pour récupérer le résultat d’une commande, on fera :
import os
commande = os.popen('ls ./', 'r') # comme pour les fichiers, 'r' ou 'w'
print commande.read() # les mêmes méthodes qu'un fichier
Voir aussi : Popen
de subprocess
Python dispose d’un module re
qui permet de manipuler des expressions rationnelles (regular expression).
Une expression rationnelle est une suite de caractères qu’on appelle plus simplement motif (pattern) pour trouver une correspondance (match). On les utilise dans le cadre d’une recherche ou d’un remplacement de texte. Les mécanismes de base pour former un motif sont basés sur des caractères spéciaux de substitution, de groupement et de quantification. Lire : fr.wikipedia.org
Exemple : un fichier texte contenant des numéros de téléphone
MARIE 04-91-85-96-34
ODILE 04-91-56-92-35
ALAIN 04-42-46-87-12
Utilisation de la fonction findall()
:
#!/usr/bin/python
# coding: utf-8
import re
fichier = open('./numtel','rb') # Ouverture du fichier en mode lecture
lignes = fichier.readlines() # Récupération du contenu du fichier
regexp = r"((0[1-9])((-[0-9]{2}){4}))"
## Traitement ligne par ligne
for ligne in lignes:
print ligne
print re.findall(regexp, ligne)
Utilisation de la fonction match()
:
#!/usr/bin/python
# coding: utf-8
import re
fichier = open('./numtel','rb') # Ouverture du fichier en mode lecture
lignes = fichier.readlines() # Récupération du contenu du fichier
regexp = r"((0[1-9])((-[0-9]{2}){4}))"
## Traitement ligne par ligne
for ligne in lignes:
#print ligne
sp = ligne.split(' ') # Séparation
if re.match(regexp, sp[1]) is not None:
print "Nom : " + sp[0] + " - Tél : " + sp[1]
else:
print "Numéro téléphone non trouvé !"
Utilisation de la fonction compile()
:
#!/usr/bin/python
# coding: utf-8
import re
fichier = open('./numtel','rb') # Ouverture du fichier en mode lecture
lignes = fichier.readlines() # Récupération du contenu du fichier
regexp = r"((0[1-9])((-[0-9]{2}){4}))"
regex = re.compile(regexp)
## Traitement ligne par ligne
for ligne in lignes:
#print ligne
sp = ligne.split(' ') # Séparation
if regex.match(sp[1]) is not None:
print "Nom : " + sp[0] + " - Tél : " + sp[1]
else:
print "Numéro téléphone non trouvé !"
Utilisation de la fonction search()
:
#!/usr/bin/python
# coding: utf-8
import re
fichier = open('./numtel','rb') # Ouverture du fichier en mode lecture
lignes = fichier.readlines() # Récupération du contenu du fichier
regexp = r"((0[1-9])((-[0-9]{2}){4}))"
## Traitement ligne par ligne
for ligne in lignes:
#print ligne
sp = ligne.split(' ') # Séparation
print re.search(regexp, sp[1]).groups()
Utilisation de la fonction search()
en donnant des noms à des groupes :
#!/usr/bin/python
# coding: utf-8
import re
fichier = open('./numtel','rb') # Ouverture du fichier en mode lecture
lignes = fichier.readlines() # Récupération du contenu du fichier
regexp = r"((0[1-9])((-[0-9]{2}){4}))"
## Traitement ligne par ligne
for ligne in lignes:
#print ligne
sp = ligne.split(' ') # Séparation
m = re.search(r"(?P<numero>(?P<indicatif>0[1-9])((-[0-9]{2}){4}))", sp[1])
print m.group('numero')
print m.group('indicatif')
Utilisation de la fonction sub()
pour remplacer le format 0X-XX-XX-XX-XX en 0X XX XX XX XX :
#!/usr/bin/python
# coding: utf-8
import re
fichier = open('./numtel','rb') # Ouverture du fichier en mode lecture
lignes = fichier.readlines() # Récupération du contenu du fichier
regexp = r"((0[1-9])((-[0-9]{2}){4}))"
## Traitement ligne par ligne
for ligne in lignes:
#print ligne
sp = ligne.split(' ') # Séparation
print re.sub(r"([0-9]{2})-([0-9]{2})-([0-9]{2})-([0-9]{2})-([0-9]{2})", r"\1 \2 \3 \4 \5", sp[1])
Python propose le module lxml
pour manipuler des fichiers XML.
XML signifie eXtensible Markup Language (Langage de balisage extensible). XML est un langage de description de documents standardisé par la spécification W3C XML 1.0 du 10/02/98.
Lien : cours XML
Un document XML bien formé signifie que le texte XML obéit aux règles syntaxiques de XML. Le document considéré comme valide (facultatif) signifie que le texte XML est bien formé et répond à une structure définie par une DTD (Definition Type Document).
Un document XML est structuré en trois parties :
Un document XML est composé d’éléments désignés par des balises et structuré sous la forme d’un arbre avec un et un seul élément racine (root). Les éléments sont aussi appelés noeuds ou nodes (par référence à la théorie des graphes).
Un prologue contient systématiquement une déclaration qui spécifie la version de XML utilisée : <?xml version="1.0" ?>
. Il existe également deux autres attributs : encoding (pour définir le type de codage du jeu de caractères) et standalone (pour préciser si une DTD est utilisée avec no).
Le fichier interfaces.xml
est le suivant :
<?xml version="1.0" encoding="UTF-8"?>
<interfaces>
<interface id="0">
<peripherique>/dev/ttyUSB0</peripherique>
</interface>
<interface id="1">
<peripherique>/dev/ttyUSB1</peripherique>
</interface>
</interfaces>
Lire le fichier interfaces.xml
:
#!/usr/bin/python
# coding: utf-8
from lxml import etree
arbre = etree.parse("interfaces.xml")
# les éléments
for interface in arbre.xpath("/interfaces/interface/peripherique"):
print(interface.text)
# les attributs
for interface in arbre.xpath("/interfaces/interface"):
print(interface.get("id"))
Écrire un fichier XML :
interfaces = etree.Element("interfaces")
# les données à exporter en XML
donnees = [
("0", "/dev/ttyUSB0", "GPS"),
("1", "/dev/ttyUSB1", "Lecteur RFID"),
("2", "/dev/ttyUSB2", "DMX"),
("3", "/dev/ttyUSB3", "NMEA 0183"),
]
# création de l'arbre des éléments
for donnee in donnees:
#print donnee
interface = etree.SubElement(interfaces, "interface")
interface.set("id", donnee[0])
peripherique = etree.SubElement(interface, "peripherique")
peripherique.text = donnee[1]
description = etree.SubElement(interface, "description")
description.text = donnee[2]
# affichage
print(etree.tostring(interfaces, pretty_print=True))
print(etree.tostring(interfaces, encoding='utf-8', method="xml", xml_declaration=True))
# écriture dans un fichier
arbre = etree.ElementTree(interfaces)
arbre.write("test.xml", encoding='utf-8', method="xml", xml_declaration=True)
Tutoriel : lxml.de
cx_Freeze
transforme un script Pythoh en exécutable (Windows, Mac ou Linux). Pour Python 2.7, il faut faire :
$ sudo apt-get install python-dev python-pip
$ sudo pip install cx_Freeze
// ou :
$ sudo pip install cx_Freeze -i https://pypi.python.org/simple
Ensuite il faut créer un fichier setup.py
:
from cx_Freeze import setup, Executable
# On appelle la fonction setup
setup(
name = "votre_programme",
version = "1",
description = "Votre programme",
executables = [Executable("votre_script.py")],
)
Puis il faut exécuter la commande suivante :
$ python setup.py build
Documentation : cx_freeze.readthedocs.org