Académique Documents
Professionnel Documents
Culture Documents
txt Page 1
Plan :
1) Rappel sur les fonctions
2) La notion de module
3) Découpage d'un programme en modules
4) Portée des variables
5) Notion d'interface de programme : API
6) Programmation orientée objet (POO) et Classes
7) Interface graphique (GUI) avec Tkinter
8) TP traceur de courbes
def nom_fonction () :
corps_de_la_fonction
Ex :
def bonjour () :
print ("Hello World!")
Tester
$ python
>>> def bonjour():
... print ("Hello World!")
...
Appel
>>> bonjour
<function bonjour at 0x2b4270>
éé> raté ! On n'a pas appelé la fonction mais demandé ce que python
connait sur "bonjour" ; c'est une function et il nous donne son adresse
dans son espace mémoire.
RQ: on peut aussi renommer la fonction (en réalité, mémoriser son adresse
dans une variable qui prend le type fonction) :
>>> x = bonjour
>>> x
<function bonjour at 0x2b4270>
>>> x()
Hello World!
RQ: comment faire une fonction vide ? avec l'instruction pass qui ne fait rien
def rien():
pass
Appel :
>>> afficher_vitesse ()
Traceback (most recent call last):
courséISNéB34év1.txt Page 2
Solutions :
é Passer une chaîne en paramètre
>>> afficher_vitesse ("dix")
Ma vitesse est de dix km/h
ou encore
Exemple :
def vitesse_est_depassee (v, vmax):
if v > vmax:
return True
else:
return False
é Paramètres optionnels
Ex:
def essai (x, y, z=21, t=34):
print ("x = %d y = %d z = %d t = %d" % (x, y, z, t))
2) La notion de module
é En mode interactif, des que l'on quitte python, les fcts que l'on a tapées
sont perdues. Une solution est de les enregistrer dans un fichier .py ;
on appelle alors ce fichier un module.
é Espaces de noms
Un espace de nom est un dictionnaire dans lequel sont stockées les noms
de variables, de fonctions, etc. Le but est d'éviter des conflits de noms.
Le nom d'un module est accessible avec __name__ dans son propre espace
de noms :
def afficher_nom_module():
print (__name__)
RQ: on peut afficher les symboles d'un espace de nom (sans les builtin) avec
dir() # dans l'espace courant
dir(nom_du_module) # dans l'espace du module
(quitter et relancer)
>>> from vitesse import afficher_vitesse
>>> afficher_vitesse (50)
Ma vitesse est de 50 km/h
>>> vitesse.afficher_vitesse(50)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'vitesse' is not defined
éé> C'est normal, il n'est pas dans l'espace de nom "vitesse" (qui n'existe pas)
courséISNéB34év1.txt Page 5
.
Les "import" et "from .. import" ne sont pas équivalents.
On peut cumuler les 2 imports (ça ira dans 2 espaces de noms différents,
donc pas de conflits).
Toujours préférer "import" sur "from ... import", car dans la seconde
méthode on va mélanger les fonctions et variables du module avec celle de
l'espace courant éé> dangereux, sauf si on s'y prend bien en préfixant
tout éé> autant faire "import".
Plusieurs approches :
é découper le problème en modules et fcts = "approche descendante"
é écrire des fcts et modules puis les assembler = "approche ascendante"
Ex (1) :
titi.py | titi.py | titi.py
import toto | from toto import * | import toto
toto.tata.hop() | hop() | toto.hop()
| |
toto.py | toto.py | toto.py
import tata | from tata import * | from tata import *
| |
tata.py | idem | idem
def hop(): | |
print ("hopla") | |
| |
$ python titi.py | idem | idem
hopla | |
éé> Dans les 2e et 3e solutions, pas besoin de savoir que tata est importée
dans toto.
Ex (2) :
titi.py
if 1 == 1 :
import toto
else:
import tata
hop()
courséISNéB34év1.txt Page 6
toto.py
def hop():
print ("Bonjour")
tata.py
def hop():
print ("Salut")
Ex :
titi.py
print ("titi 1")
import toto
print ("titi 2")
def gros_minet():
print ("miaou !")
print ("titi 3")
toto.py
print ("toto 1")
def gros_chien():
print ("ouaf !")
print ("toto 2")
$ python titi.py
titi 1
toto 1
toto 2
titi 2
titi 3
RQ: tous les print que l'on fait permer de "tracer" le programme ;
c'est une technique de mise au point et d'exploration, simple et efficace !
Ex :
titi.py
import toto
def gros_minet():
print ("miaou !")
toto.py
def gros_chien():
print ("ouaf !")
$ python titi.py
éé> rien !
# Programme principal
gros_minet()
toto.gros_chien()
toto.py
idem
$ python titi.py
courséISNéB34év1.txt Page 7
miaou !
ouaf !
def gros_ours():
print ("gromf !")
def fct_principale():
gros_minet()
toto.gros_chien()
if __name__ == "__main__":
fct_principale()
toto.py
idem
$ python titi.py
miaou !
ouaf !
tutu.py
import titi
titi.gros_ours()
$ python tutu.py
gromf !
Sinon :
é il crée un nouvel objet module vide (en gros, un dictionnaire)
é il insère cet objet module dans sys.modules
é si le module n'a pas été compilé, il le compile et l'enregistre
dans le fichier nom_du_modume.pyc ; si ce fichier existe déjà mais
qu'il est plus vieux que le module, il est recompilé.
é il charge le fichier .pyc (contient du bytecode python)
é il execute le module dans son espace de nom.
éé> On peut donc importer des modules sans crainte de faire des erreurs si
é on importe le module 2 fois (a importe b et c, b importe c)
é on fait des imports cycliques (a importe b qui importe a)
ga/bu.py
def affibu():
print ("Bu !")
ga/zo.pu
def affizo():
print ("Zo !")
ga/__init__.py
from bu import *
from zo import *
__all__ = ["bu", "zo"] # pour aider Python lors d'un "from ga import *"
meu.py ou encore :
import ga | from ga import *
ga.affibu() | affibu()
ga.affizo() | affizo()
a = 25
def f():
print (a)
>>> f()
25
def g():
b = 30
print (b)
>>> b
NameError: name 'b' is not defined
courséISNéB34év1.txt Page 9
>>> g()
30
>>> b
NameError: name 'b' is not defined
c = 20
def h():
c = 30
print (c)
>>> c
20
>>> h()
30
>>> c
20
éé> dans h(), affecter c crée une variable dans l'espace de nom de la fct ;
cette variable "masque" alors la variable c de l'espace global.
c = 20
def h():
global c
c = 30
print (c)
>>> c
20
>>> h()
30
>>> c
30
def i():
global d
d = 60
>>> d
NameError: name 'd' is not defined
>>> i()
>>> d
60
éé> comme l'espace global ne contient pas d, et que d est déclarée globale,
elle est créé dans l'espace global.
def j():
global e
>>> j()
>>> e
NameError: name 'e' is not defined
global f
f = 70
def k():
f = 80
>>> f
70
>>> k()
>>> f
70
éé> l'étiquette "global" n'est pas transmise dans les fcts ; il faut chaque
courséISNéB34év1.txt Page 10
Exercice :
h = 20
def x():
global h
h = 30
def y():
x()
h = 40
>>> y()
que vaut maintenant h ? (réponse : 30)
riri.py
a = 30
def f():
print (a)
$ python
>>> import riri
>>> a
NameError: name 'a' is not defined
>>> riri.a
30
>>> riri.f()
30
>>> riri.a = 40
>>> riri.f()
40
éé> Tout est normal, a et f() résident dans l'espace de nom riri
riri.py
a = 30
def f():
global a
a = 90
print (a)
éé> l'import "from import" fait donc bien une recopie ; il interdit
donc la modification des variables globales du module depuis un
courséISNéB34év1.txt Page 11
autre module !
truc.py
# é*é coding: utfé8 é*é
a = 5
_b = 7
def x():
print ("fct publique")
def _y():
print ("fct privée")
éé> from ... import n'importe pas ce qui est préfixé par '_' dans l'espace
de nom courant.
Mais :
>>> import truc
>>> truc.a
5
>>> truc._b
7
>>> truc.x()
fct publique
>>> truc._y()
fct privée
éé> ce n'est pas vraiment une protection, mais une indication au programmeur.
é Setter et getter
On a vu que les variables d'un module sont globales aux module mais
que il vaut mieux éviter de les modifier de l'extérieur (céaéd d'un autre
module, de __main__ ou de l'interpréteur).
setter et les getter. Du coup, toutes ces variables peuvent être privées !
Ex :
foo.py
_bar = 10
def set_bar(val):
global _bar # sinon on va créer une var locale !!
_bar = val
def get_bar():
return _bar # on aurait pu la déclarer globale par prudence
é Documentation :
Chaque fonction publique doit être documentée. On peut mettre des explications
en commentaires avant la fonction, mais c'est encore mieux d'utiliser le
mécanisme de documentation intégrée à Python : les docstring
>>> carre(3)
9
>>> carre.__doc__
'Calcule le carr\xc3\xa9 de x.\n\n Cette fonction prend en argument
un nombre x ;\n Elle renvoie le carr\xc3\xa9 de x.'
>>> help(carre)
Help on function carre in module __main__:
carre(x)
Calcule le carré de x.
é Versions
é Tests
Il faut écrire des batteries de tests pour chaque fonction, surtout avec
des langages de typage dynamique comme python. Il suffit alors de lancer les
tests pour trouver les éventuelles régressions.
On appelle ces tests des "tests unitaires". Ils sont importants lorsqu'on
développe à plusieurs ou lorsqu'on distribue un module. Il faut les écrire
très "tôt", avant même le code des fonctions !
Voir http://docs.python.org/library/unittest.html
é Les classes
Un avantage d'une classe sur un module est que l'on peut instancier plusieurs
fois une classe, chaque instance ayant ses propres variables.
class MaClasse:
"""Ma premiere classe."""
i = 12345
def f(self):
print ("La valeur de i est %d" % self.i)
Instancier la classe :
>>> x = MaClasse()
Afficher la docummentation :
>>> help(x) # ou help(MaClasse)
class MaClasse
| Ma premiere classe.
|
| Methods defined here:
|
| f(self)
|
| éééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééé
| Data and other attributes defined here:
|
| i = 12345
(END)
class A:
i = 21
def f(self):
print ("hop")
>>> help(A)
Help on class A ...
>>> dir(A)
['__doc__', '__module__', 'f', 'i']
courséISNéB34év1.txt Page 15
>>> a = A()
>>> dir(a)
['__doc__', '__module__', 'f', 'i']
On ajoute un attribut :
>>> A.b = 32 # à a classe et à toutes les instances
>>> a.c = 41 # à cette instance
>>> dir(A)
['__doc__', '__module__', 'b', 'f', 'i']
>>> dir(a)
['__doc__', '__module__', 'b', 'c', 'f', 'i']
é Constructeurs et destructeurs :
Déclarer un constructeur :
def __init__(self):
self.i = 33
>>> x = MaClasse(32)
>>> x.f()
La valeur de i est 32
>>> y = MaClasse()
TypeError: __init__() takes exactly 2 arguments (1 given)
Déclarer un destructeur :
class Toto:
def __del__(self):
print ("Instance de Toto détruite !")
>>> x = Toto()
>>> del(x)
Instance de Toto détruite !
é Héritage :
class Mere:
i = 22
def f(self):
print ("Coucou")
class Fille(Mere):
j = 33
def g(self):
print ("Hopla")
m = Mere()
>>> m.i
22
>>> m.f()
Coucou
>>> m.j
AttributeError: Mere instance has no attribute 'j'
>>> m.h()
AttributeError: Mere instance has no attribute 'h'
>>> e = Fille()
>>> e.i
22
>>> e.j
33
>> e.f()
Coucou
>>> e.g()
Hopla
class Mere:
def __init__(self):
print ("Coucou")
class Fille(Mere):
def __init__(self):
Mere.__init__(self)
print ("Hopla")
>>> e = Fille()
Coucou
Hopla
class C():
_x = 1 # attribut privé
def getx(self):
return self._x
courséISNéB34év1.txt Page 17
Python propose de nombreux GUI toolkit, des plus simples aux plus
complets (PyGTK, PyQt, etc).
Le GUI toolkit "standard" est Tkinter (pour interéface), basé sur Tk.
Tk est une "vieille" librairie graphique issue de tcl/tk, avec un graphisme
un peu "carré", mais il est assez simple, suffisament riche, et normalement
installé en standard avec python.
Une fois que l'on maîtrise Tkinter, il est relativement aisé de passer
à un toolkit plus riche car de nombreuses notions sont communes.
http://wiki.python.org/moin/TkInter
é Première fenêtre
#! /usr/bin/env python
# é*é coding: utfé8 é*é
# Crée un conteneur
frame = Frame(root)
frame.pack()
root = Tk()
app = App(root)
root.mainloop()
class App:
def __init__(self, root):
# Crée un conteneur
frame = Frame(root)
frame.pack()
root = Tk()
app = App(root)
root.mainloop()
class App:
def __init__(self, root):
courséISNéB34év1.txt Page 19
# Conteneur principal
frame_princ = Frame(root)
frame_princ.pack(anchor=NW) # par défaut side=TOP et anchor=CENTER
root = Tk()
app = App(root)
root.mainloop()
class App:
def __init__(self, root):
# Conteneur principal
frame_princ = Frame(root)
frame_princ.pack(anchor=NW) # par défaut side=TOP et anchor=CENTER
root = Tk()
app = App(root)
root.mainloop()
class App:
def __init__(self, root):
# Conteneur principal
frame_princ = Frame(root)
frame_princ.pack(anchor=NW) # par défaut side=TOP et anchor=CENTER
root = Tk()
app = App(root)
root.mainloop()
class App:
# Conteneur principal
frame_princ = Frame(root)
frame_princ.pack(anchor=NW) # par défaut side=TOP et anchor=CENTER
root = Tk()
app = App(root)
root.mainloop()
8) TP traceur de courbes
é Evaluation d'expressions
>>> t=5
>>> eval ("2*t")
10
26
# ééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééé
class App:
# Conteneur principal
frame_princ = Frame(root)
frame_princ.pack(anchor=NW) # par défaut side=TOP et anchor=CENTER
# Les paramètres
courséISNéB34év1.txt Page 23
self.entry_fx = self.creer_entry(frame_params,
"f(x) =", "2*x*xé5*x+3", "30")
self.entry_xmin = self.creer_entry(frame_params, "xmin =", "é5", "15")
self.entry_ymin = self.creer_entry(frame_params, "ymin =", "é5", "15")
self.entry_xmax = self.creer_entry(frame_params, "xmax =", "5", "15")
self.entry_ymax = self.creer_entry(frame_params, "ymax =", "5", "15")
self.entry_nbp = self.creer_entry(frame_params,
"nb points =", "100", "15")
def creer_entry(self,owner,titre,valeur,largeur):
label = Label(owner, text=titre)
label.pack(anchor=NW)
entry = Entry(owner, width=largeur)
entry.pack(anchor=NW)
entry.delete(0, END)
entry.insert(0, valeur)
return entry
for i in range(0,nbp+1):
x = xmin+i*(xmaxéxmin)/nbp
y = float(eval(fx, {}, {"x" : x} ))
# print ("i = %d x = %d y = %d" % (i,x,y))
if i > 0:
self.canvas.create_line(
w*(oxéxmin)/(xmaxéxmin), h é h*(oyéymin)/(ymaxéymin),
w*( xéxmin)/(xmaxéxmin), h é h*( yéymin)/(ymaxéymin))
ox = x
oy = y
root = Tk()
app = App(root)
root.mainloop()
# ééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééé