modèle objet de python
This commit is contained in:
parent
2ddd3e2c18
commit
1645146d0d
|
@ -0,0 +1,94 @@
|
||||||
|
Les design patterns
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Les design patterns **ne sont pas** indépendants du langage.
|
||||||
|
Ils dépendent de l'implémentation.
|
||||||
|
|
||||||
|
Le duck typing
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
En python, le duck typing est une forme extreme de programmation par interface.
|
||||||
|
Ne pas hériter dans des directions fausse
|
||||||
|
|
||||||
|
exemple : une voiture ne peut hériter d'un moteur, parce que un moteur n'est pas une voiture.
|
||||||
|
|
||||||
|
hold or wrap ?
|
||||||
|
--------------
|
||||||
|
|
||||||
|
**hold**::
|
||||||
|
|
||||||
|
O.S.method()
|
||||||
|
|
||||||
|
Cela induit un couplage fort (cf la loi de Demeter)
|
||||||
|
|
||||||
|
.. important:: law of Demeter : never more than one dot.
|
||||||
|
|
||||||
|
wrap : a hold by private name, with a::
|
||||||
|
|
||||||
|
self.S.method()
|
||||||
|
|
||||||
|
Ou bien une méthode getattr::
|
||||||
|
|
||||||
|
__getattr__()
|
||||||
|
|
||||||
|
Gets coupling right.
|
||||||
|
|
||||||
|
|
||||||
|
wrapper can restrict, inheritance cannot restrict
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
class RestrictingWrapper(object):
|
||||||
|
|
||||||
|
def __init__(self, w, block):
|
||||||
|
self._w = w
|
||||||
|
self._block = block
|
||||||
|
|
||||||
|
def __getattr__(self, n):
|
||||||
|
if n in self._block:
|
||||||
|
raise AttributeError, n
|
||||||
|
return getattr(self._w, n)
|
||||||
|
|
||||||
|
Pattern de création : singleton
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
# utiliser un module au lieu d'une classe
|
||||||
|
|
||||||
|
in `toto.py`::
|
||||||
|
|
||||||
|
class Toto()
|
||||||
|
toto = Toto()
|
||||||
|
|
||||||
|
in another module::
|
||||||
|
|
||||||
|
from toto import toto
|
||||||
|
|
||||||
|
la factory
|
||||||
|
--------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
def load(pkg, obj):
|
||||||
|
m = __import__(pkg, {}, {}, [obj])
|
||||||
|
return getattr(m, obj)
|
||||||
|
|
||||||
|
cls = load('p1.p2.p3', 'c4')
|
||||||
|
|
||||||
|
|
||||||
|
template method (self delegation)
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
# Abstract base class::
|
||||||
|
|
||||||
|
def OrganiseMethod()
|
||||||
|
def org_method():
|
||||||
|
def do_this()
|
||||||
|
def do_that()
|
||||||
|
|
||||||
|
def Concrete(OrganiseMethod)
|
||||||
|
def do_this(): ...
|
||||||
|
def do_that(): ...
|
||||||
|
|
||||||
|
il est préférable de lever une NotImplementedError, ce qui revient à faire
|
||||||
|
une classe abstraite.
|
|
@ -1,61 +0,0 @@
|
||||||
# coding: utf-8
|
|
||||||
minuscules = 'abcdefghijklmnopqrstuvwxyz'
|
|
||||||
majuscules = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
|
||||||
|
|
||||||
def rotation(chaine, x):
|
|
||||||
"""
|
|
||||||
Effectue une rotation de x caractères vers la droite:
|
|
||||||
>>> rotation('abcde', 2)
|
|
||||||
'cdeab'
|
|
||||||
"""
|
|
||||||
return chaine[x:] + chaine[:x]
|
|
||||||
|
|
||||||
def index(c, chaine):
|
|
||||||
"""
|
|
||||||
Trouve l'index de c dans la chaine:
|
|
||||||
>>> index('n', 'bonjour')
|
|
||||||
2
|
|
||||||
"""
|
|
||||||
for i in range(len(chaine)):
|
|
||||||
if (c == chaine[i]):
|
|
||||||
return i
|
|
||||||
return -1
|
|
||||||
|
|
||||||
def chiffre_minuscules(chaine, x):
|
|
||||||
"""
|
|
||||||
Chiffre une chaîne composée de minuscules
|
|
||||||
>>> chiffre_minuscules('bonjour', 3)
|
|
||||||
'erqmrxu'
|
|
||||||
"""
|
|
||||||
r = rotation(minuscules, x)
|
|
||||||
resultat = ''
|
|
||||||
for lettre in chaine:
|
|
||||||
resultat = resultat + r[index(lettre, minuscules)]
|
|
||||||
return resultat
|
|
||||||
|
|
||||||
def chiffre(chaine, x):
|
|
||||||
"""
|
|
||||||
Chiffre une chaîne quelconque
|
|
||||||
>>> chiffre('Bonjour les amis!', 3)
|
|
||||||
'Erqmrxu ohv dplv!'
|
|
||||||
"""
|
|
||||||
r_min = rotation(minuscules, x)
|
|
||||||
r_maj = rotation(majuscules, x)
|
|
||||||
resultat = ''
|
|
||||||
for lettre in chaine:
|
|
||||||
if lettre in minuscules:
|
|
||||||
resultat = resultat + r_min[index(lettre, minuscules)]
|
|
||||||
elif lettre in majuscules:
|
|
||||||
resultat = resultat + r_maj[index(lettre, majuscules)]
|
|
||||||
else:
|
|
||||||
resultat = resultat + lettre
|
|
||||||
return resultat
|
|
||||||
|
|
||||||
#############################################################################
|
|
||||||
# Programme principal
|
|
||||||
#############################################################################
|
|
||||||
print(chiffre_minuscules('bonjour', 3))
|
|
||||||
print(chiffre('Bonjour les amis!', 3))
|
|
||||||
print(chiffre('Erqmrxu ohv dplv!', 23))
|
|
||||||
print(chiffre('Eudyr, yrxv dyhc ilql fhw hahuflfh!', 23))
|
|
||||||
|
|
|
@ -0,0 +1,452 @@
|
||||||
|
Définir et manipuler des classes
|
||||||
|
=================================
|
||||||
|
|
||||||
|
.. glossary::
|
||||||
|
|
||||||
|
objet
|
||||||
|
|
||||||
|
Un object est une entité possédant un type, un état, et un comportement.
|
||||||
|
Un object correspondant généralement à une entité du monde réel, mais
|
||||||
|
cette entité peut être abstraite.
|
||||||
|
On parle aussi d'**instance**.
|
||||||
|
|
||||||
|
**état d'un objet** : ensemble de propriétés auxquelles sont associées des
|
||||||
|
valeurs.
|
||||||
|
|
||||||
|
Les variables de l'objet sont appelées des **attributs**.
|
||||||
|
le comportement d'un :term:`objet` :
|
||||||
|
|
||||||
|
- des actions effectuées sur l'objet
|
||||||
|
- des appels faits sur l'objet
|
||||||
|
|
||||||
|
envois de messages à l'objet = appel de **méthodes**
|
||||||
|
|
||||||
|
programmation objet (première approche)
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
- le type et le protocole d'un objet sont définis par sa classe
|
||||||
|
- une classe possède un ensemble d'attributs et de méthodes
|
||||||
|
|
||||||
|
deux relations possibles
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
.. glossary::
|
||||||
|
|
||||||
|
heritage
|
||||||
|
|
||||||
|
relation "est une espèce de " utilisée entre une classe et une autre classe
|
||||||
|
|
||||||
|
instantiation
|
||||||
|
|
||||||
|
relation "est une instance de " entre un objet et une classe
|
||||||
|
|
||||||
|
|
||||||
|
- est une instance de (objets par rapport à classe)
|
||||||
|
- est une espèce de (classe par rapport à classe, :term:`heritage`)
|
||||||
|
|
||||||
|
**instance**
|
||||||
|
|
||||||
|
- définition d'une classe
|
||||||
|
- instance de classe : on peut créer des objets à partir d'un type "classe"
|
||||||
|
(une classe est instanciable)
|
||||||
|
|
||||||
|
>>> class A:
|
||||||
|
... pass
|
||||||
|
...
|
||||||
|
>>> a = A()
|
||||||
|
|
||||||
|
:term:`heritage` : notation en python
|
||||||
|
|
||||||
|
>>> class A: pass
|
||||||
|
...
|
||||||
|
>>> class B(A): pass
|
||||||
|
...
|
||||||
|
>>> b = B()
|
||||||
|
>>> type(b) == B
|
||||||
|
>>> isinstance(b, A) == True
|
||||||
|
|
||||||
|
possibilité en python d'héritage multiple::
|
||||||
|
|
||||||
|
class A(B, C): pass
|
||||||
|
|
||||||
|
|
||||||
|
attribut d'objets et de classes
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
>>> o = object()
|
||||||
|
>>> o
|
||||||
|
<object object at 0x7f77c9cda0d0>
|
||||||
|
>>> class C(object): pass
|
||||||
|
...
|
||||||
|
>>> class C: pass
|
||||||
|
...
|
||||||
|
>>> c = C()
|
||||||
|
>>> c.a = 3
|
||||||
|
>>> c.a
|
||||||
|
3
|
||||||
|
>>> vars(c)
|
||||||
|
{'a': 3}
|
||||||
|
>>> c.__dict__
|
||||||
|
{'a': 3}
|
||||||
|
>>> C.__dict__
|
||||||
|
{'__module__': '__main__', '__doc__': None}
|
||||||
|
>>> C.c = 5
|
||||||
|
>>> C.__dict__
|
||||||
|
{'c': 5, '__module__': '__main__', '__doc__': None}
|
||||||
|
>>> c.c
|
||||||
|
5
|
||||||
|
>>> c.z = 3
|
||||||
|
>>> c.z
|
||||||
|
3
|
||||||
|
>>> c.__dict__
|
||||||
|
{'a': 3, 'z': 3}
|
||||||
|
>>> C.__dict__
|
||||||
|
{'c': 5, '__module__': '__main__', '__doc__': None}
|
||||||
|
>>> class MaKlass:
|
||||||
|
... def unefonction(self, x):
|
||||||
|
... print x
|
||||||
|
...
|
||||||
|
>>> MaKlass.__dict__
|
||||||
|
{'__module__': '__main__', '__doc__': None, 'unefonction': <function unefonction at 0x7f77c5b0c488>}
|
||||||
|
>>> k = MaKlass()
|
||||||
|
>>> k.__dict__
|
||||||
|
{}
|
||||||
|
>>> def autrefonc(self, x)
|
||||||
|
File "<stdin>", line 1
|
||||||
|
def autrefonc(self, x)
|
||||||
|
^
|
||||||
|
SyntaxError: invalid syntax
|
||||||
|
>>> def autrefonc(self, x):
|
||||||
|
... print x
|
||||||
|
...
|
||||||
|
>>> k.autrefonc = autrefonc
|
||||||
|
>>> k.__dict__
|
||||||
|
{'autrefonc': <function autrefonc at 0x7f77c5b0c500>}
|
||||||
|
>>> MaKlass.__dict__
|
||||||
|
{'__module__': '__main__', '__doc__': None, 'unefonction': <function unefonction at 0x7f77c5b0c488>}
|
||||||
|
>>> MaKlass.unefonction(k, "toto")
|
||||||
|
toto
|
||||||
|
>>> k.unefonction("toto")
|
||||||
|
toto
|
||||||
|
>>> k.__dict__
|
||||||
|
{'autrefonc': <function autrefonc at 0x7f77c5b0c500>}
|
||||||
|
>>> MaKlass.toto = "test"
|
||||||
|
>>> k.__dict__
|
||||||
|
{'autrefonc': <function autrefonc at 0x7f77c5b0c500>}
|
||||||
|
>>> k.toto
|
||||||
|
'test'
|
||||||
|
>>>
|
||||||
|
|
||||||
|
|
||||||
|
le __dict__ avec l'héritage de classe
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
>>> class A(object): pass
|
||||||
|
...
|
||||||
|
>>> A.__dict__
|
||||||
|
dict_proxy({'__dict__': <attribute '__dict__' of 'A' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None})
|
||||||
|
>>> class B(A):
|
||||||
|
... b = 3
|
||||||
|
...
|
||||||
|
>>> class C(B):
|
||||||
|
... c = 2
|
||||||
|
...
|
||||||
|
>>> c = C()
|
||||||
|
>>> o = C()
|
||||||
|
>>> o.__dict__
|
||||||
|
{}
|
||||||
|
>>> o.c
|
||||||
|
2
|
||||||
|
>>> o.b
|
||||||
|
3
|
||||||
|
>>> o.__class__
|
||||||
|
<class '__main__.C'>
|
||||||
|
>>> o.__class__.__dict__
|
||||||
|
dict_proxy({'__module__': '__main__', 'c': 2, '__doc__': None})
|
||||||
|
>>>
|
||||||
|
|
||||||
|
|
||||||
|
method resolution object
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
>>> class A(object): pass
|
||||||
|
...
|
||||||
|
>>> A.__mro__
|
||||||
|
(<class '__main__.A'>, <type 'object'>)
|
||||||
|
>>> class B(A): pass
|
||||||
|
...
|
||||||
|
>>> B.__mro__
|
||||||
|
(<class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
|
||||||
|
>>> class C(A, B): pass
|
||||||
|
...
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "<stdin>", line 1, in <module>
|
||||||
|
TypeError: Error when calling the metaclass bases
|
||||||
|
Cannot create a consistent method resolution
|
||||||
|
order (MRO) for bases A, B
|
||||||
|
>>>
|
||||||
|
|
||||||
|
|
||||||
|
introspection contre encapsulation
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
voir un objet comme un espace de nommage. C'est plus **agile**.
|
||||||
|
|
||||||
|
attributs et méthodes vus comme des ajouts dans l'espace de nommage
|
||||||
|
|
||||||
|
>>> a.a = 2
|
||||||
|
>>> def function(x):
|
||||||
|
... print x
|
||||||
|
...
|
||||||
|
>>> a.f = function
|
||||||
|
>>> a.f("hello")
|
||||||
|
hello
|
||||||
|
>>>
|
||||||
|
|
||||||
|
|
||||||
|
la nécessité d'un design objet
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
affichage d'une calculette, il faut créer un type `Touche`
|
||||||
|
qui contient deux désignations : `Chiffre` et `operation`::
|
||||||
|
|
||||||
|
type operation = Plus | Moins | Divise
|
||||||
|
type touche = Chiffre of int | Memoire | Op of operation
|
||||||
|
|
||||||
|
soit, on définit un type touche, soit on ne définit pas ce type::
|
||||||
|
|
||||||
|
type operation = Plus | Moins | Divise
|
||||||
|
type memoire = Memoire
|
||||||
|
type chiffre = Chiffre
|
||||||
|
|
||||||
|
- les structures de données (int, str, list, dict...) : types de base
|
||||||
|
- les structures de données utilisateur : les classes !
|
||||||
|
|
||||||
|
.. function:: type (objname)
|
||||||
|
|
||||||
|
:param objname: l'objet dont on veut connaître le type
|
||||||
|
|
||||||
|
Manipulations sur les classes et les objets
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
En python un type et une classe c'est la même chose. Une classe
|
||||||
|
est un type standard. En python tout est objet, et tout provient d'un seul objet
|
||||||
|
(qui s'appelle ``object``).
|
||||||
|
|
||||||
|
- encapsulation (cacher les attributs (variables d'état)) d'un objet.
|
||||||
|
|
||||||
|
- interfaces : chaque aspect d'une classe peut être vu comme une interface.
|
||||||
|
|
||||||
|
Une interface décrit un ensemble de comportements.
|
||||||
|
on peut considérer une interface comme un protocole d'utilisation d'un objet
|
||||||
|
dans un contexte donné.
|
||||||
|
|
||||||
|
on peut alors créer des outils qui sauront traiter n'importe quel objet
|
||||||
|
pourvu qu'il respecte une ensemble d'interfaces.
|
||||||
|
|
||||||
|
.. todo:: travailler l'héritage, l'aggrégation, la délégation
|
||||||
|
|
||||||
|
Voici un exemple de classe `Voiture` :
|
||||||
|
|
||||||
|
.. literalinclude:: snippets/heritage.py
|
||||||
|
:pyobject: Voiture
|
||||||
|
|
||||||
|
j'instancie ma classe `Voiture` :
|
||||||
|
|
||||||
|
>>> ma_voiture = Voiture("ma_marque", "150km/h")
|
||||||
|
>>> ma_voiture.roule()
|
||||||
|
'vroummm'
|
||||||
|
>>> ma_voiture.signaletique()
|
||||||
|
'constructeur : ma_marque, vitesse_max 150km/h'
|
||||||
|
|
||||||
|
.. todo:: faire des traitements dans l'init
|
||||||
|
|
||||||
|
- héritage (est une sorte de)
|
||||||
|
- polymorphisme : un objet apparait comme une instance d'une classe parente
|
||||||
|
|
||||||
|
.. literalinclude:: snippets/heritage.py
|
||||||
|
:pyobject: Turbo
|
||||||
|
|
||||||
|
>>> v = DoDoche("marque", 160)
|
||||||
|
>>> v.get_prix()
|
||||||
|
'7000'
|
||||||
|
>>> isinstance(v, Prix)
|
||||||
|
True
|
||||||
|
>>>
|
||||||
|
|
||||||
|
mais l'objet conserve son identité :
|
||||||
|
|
||||||
|
>>> type(v)
|
||||||
|
<type 'Voiture'>
|
||||||
|
|
||||||
|
la fonction ``achete_voiture()`` sera appelée indépendamment du type de l'objet,
|
||||||
|
du moment que l'objet a une méthode `get_prix()`, c'est le duck typing, qu'il
|
||||||
|
est préférable de ramener au polymorphisme d'objet, ou bien utiliser les :mod:`abc`
|
||||||
|
(abstract base classes).
|
||||||
|
|
||||||
|
.. literalinclude:: snippets/heritage.py
|
||||||
|
:pyobject: achete_voiture
|
||||||
|
|
||||||
|
tout le code :
|
||||||
|
|
||||||
|
.. literalinclude:: snippets/heritage.py
|
||||||
|
|
||||||
|
:download:`télécharger le code <snippets/heritage.py>`
|
||||||
|
|
||||||
|
- **l'aggrégation**
|
||||||
|
|
||||||
|
un attribut est lui-même un objet (ce qui est fréquent en python)...
|
||||||
|
|
||||||
|
.. literalinclude:: snippets/aggregation.py
|
||||||
|
|
||||||
|
- **la délégation**
|
||||||
|
|
||||||
|
la fonction "property" est un élément du design de python lui-même
|
||||||
|
|
||||||
|
.. function:: property()
|
||||||
|
|
||||||
|
les patrons de conception
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
- le patron **factory**
|
||||||
|
|
||||||
|
.. literalinclude:: snippets/patrons.py
|
||||||
|
|
||||||
|
:download:`télécharger usine (factory) <snippets/patrons.py>`
|
||||||
|
|
||||||
|
- le patron **wrapper**
|
||||||
|
|
||||||
|
:download:`télécharger wrapper <snippets/wrap.py>`
|
||||||
|
|
||||||
|
.. literalinclude:: snippets/wrap.py
|
||||||
|
|
||||||
|
exemple d'utilisation de `Wrap()`
|
||||||
|
|
||||||
|
>>> class O:
|
||||||
|
... pass
|
||||||
|
...
|
||||||
|
>>> o = O()
|
||||||
|
>>> o.a = "blah"
|
||||||
|
>>>
|
||||||
|
>>> from wrap import Wrap
|
||||||
|
>>> w = Wrap("monwrap", o)
|
||||||
|
>>> w._name
|
||||||
|
'monwrap'
|
||||||
|
>>> w._w
|
||||||
|
<__main__.O instance at 0x7fbf177aaa28>
|
||||||
|
>>> w._w.a
|
||||||
|
'blah'
|
||||||
|
>>> w.a
|
||||||
|
'blah'
|
||||||
|
>>> w.u
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "<stdin>", line 1, in <module>
|
||||||
|
File "wrap.py", line 11, in __getattr__
|
||||||
|
return getattr(self._w, name)
|
||||||
|
AttributeError: O instance has no attribute 'u'
|
||||||
|
>>>
|
||||||
|
|
||||||
|
- le patron de conception **itérable**
|
||||||
|
|
||||||
|
:download:`télécharger iterable <snippets/iterable.py>`
|
||||||
|
|
||||||
|
.. literalinclude:: snippets/iterable.py
|
||||||
|
|
||||||
|
- le patron **decorateur**
|
||||||
|
|
||||||
|
:download:`télécharger decorateur <snippets/decorateur.py>`
|
||||||
|
|
||||||
|
.. literalinclude:: snippets/decorateur.py
|
||||||
|
|
||||||
|
>>> def deco(func):
|
||||||
|
... func.attr = 'decorated'
|
||||||
|
... return func
|
||||||
|
...
|
||||||
|
>>> @deco
|
||||||
|
... def f(): pass
|
||||||
|
...
|
||||||
|
>>> f.attr
|
||||||
|
'decorated'
|
||||||
|
>>>
|
||||||
|
|
||||||
|
autre exemple : les méthodes statiques
|
||||||
|
|
||||||
|
>>> class A(object):
|
||||||
|
... @staticmethod
|
||||||
|
... def my_class_method(cls):
|
||||||
|
... # do stuff here
|
||||||
|
|
||||||
|
|
||||||
|
métaclasses
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
>>> class A:
|
||||||
|
... pass
|
||||||
|
...
|
||||||
|
>>> type(A)
|
||||||
|
<type 'classobj'>
|
||||||
|
>>> class B(object): pass
|
||||||
|
...
|
||||||
|
>>> type(B)
|
||||||
|
<type 'type'>
|
||||||
|
>>> help(type)
|
||||||
|
|
||||||
|
>>> C = type('C', (), {})
|
||||||
|
>>> C
|
||||||
|
<class '__main__.C'>
|
||||||
|
>>>
|
||||||
|
|
||||||
|
>>> type(object)
|
||||||
|
<type 'type'>
|
||||||
|
>>> type(type)
|
||||||
|
<type 'type'>
|
||||||
|
>>> isinstance(type, object)
|
||||||
|
True
|
||||||
|
>>> isinstance(object, type)
|
||||||
|
True
|
||||||
|
>>>
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
class MaMetaClasse(type):
|
||||||
|
"""Exemple d'une métaclasse."""
|
||||||
|
def __new__(metacls, nom, bases, dict):
|
||||||
|
"""Création de notre classe."""
|
||||||
|
print("On crée la classe {}".format(nom))
|
||||||
|
return type.__new__(metacls, nom, bases, dict)
|
||||||
|
|
||||||
|
class MaClasse(object):
|
||||||
|
__metaclass__ = MaMetaClasse
|
||||||
|
|
||||||
|
|
||||||
|
exemple : forcer l'implémentation d'un singleton avec les métaclasses
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
class Singleton(type):
|
||||||
|
instance = None
|
||||||
|
def __call__(cls, *args, **kw):
|
||||||
|
if not cls.instance:
|
||||||
|
cls.instance = super(Singleton, cls).__call__(*args, **kw)
|
||||||
|
return cls.instance
|
||||||
|
|
||||||
|
class ASingleton(object):
|
||||||
|
__metaclass__ = Singleton
|
||||||
|
|
||||||
|
a = ASingleton()
|
||||||
|
b = ASingleton()
|
||||||
|
assert a is b
|
||||||
|
print(a.__class__.__name__, b.__class__.__name__)
|
||||||
|
|
||||||
|
class BSingleton(object):
|
||||||
|
__metaclass__ = Singleton
|
||||||
|
|
||||||
|
c = BSingleton()
|
||||||
|
d = BSingleton()
|
||||||
|
assert c is d
|
||||||
|
print(c.__class__.__name__, d.__class__.__name__)
|
||||||
|
assert c is not a
|
||||||
|
|
|
@ -29,7 +29,7 @@ import os
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
# ones.
|
# ones.
|
||||||
extensions = [
|
extensions = [
|
||||||
'sphinx.ext.pngmath', 'sphinx.ext.ifconfig',
|
'sphinx.ext.pngmath', 'sphinx.ext.ifconfig', 'sphinx.ext.todo',
|
||||||
]
|
]
|
||||||
|
|
||||||
# ajout des cours avec solution des exercices ou non
|
# ajout des cours avec solution des exercices ou non
|
||||||
|
@ -40,6 +40,7 @@ def setup(app):
|
||||||
exercice = False
|
exercice = False
|
||||||
correction = False
|
correction = False
|
||||||
|
|
||||||
|
todo_include_todos = True
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,12 @@ Introduction à l'algorithmique
|
||||||
|
|
||||||
presentation
|
presentation
|
||||||
fondement
|
fondement
|
||||||
|
mechanism
|
||||||
|
prompt
|
||||||
langage
|
langage
|
||||||
programme
|
programme
|
||||||
modularite
|
modularite
|
||||||
modules
|
modules
|
||||||
|
classes
|
||||||
|
DesignPatterns
|
||||||
annexes/index
|
annexes/index
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
Interactions avec l'utilisateur
|
||||||
|
===============================
|
||||||
|
|
||||||
|
les prompts
|
||||||
|
--------------
|
||||||
|
|
||||||
|
`raw_input` ou `input`
|
||||||
|
|
||||||
|
(raw_input renvoie une string, input essayes d'évaluer, soyez prudent...)
|
||||||
|
|
||||||
|
>>> from subprocess import call
|
||||||
|
>>> filename = input("quel fichier voulez-vous afficher ?\n")
|
||||||
|
>>> call("cat " + filename, shell=True)
|
||||||
|
|
||||||
|
.. _cmdlabel:
|
||||||
|
|
||||||
|
le module :mod:`cmd` et les interpréteurs
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
le monde des interpréteur ligne de commande...
|
||||||
|
|
||||||
|
Peu après l'âge de bronze vint le temps de l'interpréteur ligne de commande,
|
||||||
|
c'est-à-dire quelque chose de plus spécifique que **l'application ligne de commande**,
|
||||||
|
ou que l'utilitaire ligne de commande.
|
||||||
|
|
||||||
|
|
||||||
|
Un interpréteur ligne de commande est un programme qui :
|
||||||
|
|
||||||
|
- est forcément plein texte
|
||||||
|
- vous donne un prompt
|
||||||
|
- prends toutes ses entrées d'un coup
|
||||||
|
- produit une sortie (typiquement des lignes de texte)
|
||||||
|
- vous redonne un prompt
|
||||||
|
|
||||||
|
Le shell unix est un bon exemple d'interpréteur ligne de commande.
|
||||||
|
|
||||||
|
Un utilitaire ligne de commande est un programme unix-like qui prend toutes
|
||||||
|
les entrées d'un coup, et qui vous renvoie une sortie d'un coup.
|
||||||
|
|
||||||
|
le module :mod:`cmd` : exemple d'utilisation
|
||||||
|
|
||||||
|
.. module:: cmd
|
||||||
|
:synopsis: interpréteur ligne de commande
|
||||||
|
|
||||||
|
.. literalinclude:: snippets/cli.py
|
||||||
|
|
||||||
|
:download:`telecharger cmd <snippets/cli.py>`
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
>>> from cli import Cli
|
||||||
|
>>> prompt = Cli()
|
||||||
|
>>> prompt.cmdloop()
|
||||||
|
cli (command line interpreter)
|
||||||
|
(type help or ? for commands list)
|
||||||
|
#Prompt> ?
|
||||||
|
|
||||||
|
Documented commands (type help <command>):
|
||||||
|
==========================================
|
||||||
|
EOF exit
|
||||||
|
|
||||||
|
Undocumented commands:
|
||||||
|
======================
|
||||||
|
cmd help quit
|
||||||
|
|
||||||
|
#Prompt>
|
||||||
|
|
||||||
|
pour ajouter une commande, utiliser simplement l'héritage::
|
||||||
|
|
||||||
|
>>> from cli import Cli
|
||||||
|
>>> class Prompt(Cli):
|
||||||
|
... def do_hello(self, line):
|
||||||
|
... print "hello %s", line
|
||||||
|
...
|
||||||
|
>>> prompt = Prompt()
|
||||||
|
>>> prompt.cmdloop()
|
||||||
|
cli (command line interpreter)
|
||||||
|
(type help or ? for commands list)
|
||||||
|
#Prompt> ?
|
||||||
|
|
||||||
|
Documented commands (type help <command>):
|
||||||
|
==========================================
|
||||||
|
EOF exit
|
||||||
|
|
||||||
|
Undocumented commands:
|
||||||
|
======================
|
||||||
|
cmd hello help quit
|
||||||
|
|
||||||
|
#Prompt> hello world
|
||||||
|
|
||||||
|
|
||||||
|
.. todo:: faire un petit projet d'interpréteur ligne de commande du jeu C+/C-
|
||||||
|
|
||||||
|
lire et écrire dans un fichier
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
les **handle de fichier** (file handles)
|
||||||
|
|
||||||
|
|
||||||
|
>>>
|
||||||
|
>>> fh = file('test', 'w')
|
||||||
|
>>> fh.write('hello world')
|
||||||
|
>>> fh.close()
|
||||||
|
>>> content = file('test', 'r').read()
|
||||||
|
>>> content
|
||||||
|
'hello world'
|
||||||
|
>>>
|
|
@ -0,0 +1,8 @@
|
||||||
|
class A:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class B:
|
||||||
|
pass
|
||||||
|
|
||||||
|
a = A()
|
||||||
|
a.b = B()
|
|
@ -0,0 +1,73 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf8 -*-
|
||||||
|
"""Command line interpreter
|
||||||
|
"""
|
||||||
|
import cmd
|
||||||
|
|
||||||
|
# ____________________________________________________________
|
||||||
|
# this Cli is a model of a basic use of a simple cmd
|
||||||
|
class Cli(cmd.Cmd):
|
||||||
|
def __init__(self):
|
||||||
|
cmd.Cmd.__init__(self)
|
||||||
|
self.doc_header = "Documented commands (type help <command>):"
|
||||||
|
self.undoc_header = "Undocumented commands"
|
||||||
|
self.prompt = "#Prompt> "
|
||||||
|
self.intro = """cli (command line interpreter)
|
||||||
|
(type help or ? for commands list)"""
|
||||||
|
self.ruler = "-"
|
||||||
|
|
||||||
|
def emptyline(self):
|
||||||
|
print "Type 'exit' to finish withe the session or type ? for help."
|
||||||
|
|
||||||
|
def default(self, line):
|
||||||
|
print "unknown command prefix"
|
||||||
|
print "*** unknown syntax : %s (type 'help' for help for a list of valid commands)"%line
|
||||||
|
self.emptyline()
|
||||||
|
|
||||||
|
def do_exit(self, line):
|
||||||
|
"""Exits from the console"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
def do_quit(self, line):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def do_EOF(self, args):
|
||||||
|
"""Exit on system end of file character"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
# ____________________________________________________________
|
||||||
|
# commands pre and post actions
|
||||||
|
# def precmd(self, line):
|
||||||
|
# return line
|
||||||
|
# def postcmd(self, stop, line):
|
||||||
|
# # if there is a problem, just return True : it stops everythings
|
||||||
|
# stop = True
|
||||||
|
# return stop # quit if stop == True
|
||||||
|
# ____________________________________________________________
|
||||||
|
# program pre and post actions
|
||||||
|
# def preloop(self):
|
||||||
|
# # action for the beginning of the program
|
||||||
|
# pass
|
||||||
|
|
||||||
|
# def postloop(self):
|
||||||
|
# # action for the end of the program
|
||||||
|
# print "exit cli"
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
||||||
|
class HelloCli(Cli):
|
||||||
|
|
||||||
|
def input_hello(self, line):
|
||||||
|
return line.replace(",", " and ")
|
||||||
|
|
||||||
|
def output_hello(self, result):
|
||||||
|
print result
|
||||||
|
|
||||||
|
def do_hello(self, line):
|
||||||
|
self.output_hello("hello, " + self.input_hello(line))
|
||||||
|
#return False # if you want to stay into the cli
|
||||||
|
return True # if you want to exit
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
prompt = HelloCli()
|
||||||
|
prompt.cmdloop("intro, modifies Cmd.intro")
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Module docstring.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import optparse
|
||||||
|
|
||||||
|
def process_command_line(argv):
|
||||||
|
"""
|
||||||
|
Return a 2-tuple: (settings object, args list).
|
||||||
|
`argv` is a list of arguments, or `None` for ``sys.argv[1:]``.
|
||||||
|
"""
|
||||||
|
if argv is None:
|
||||||
|
argv = sys.argv[1:]
|
||||||
|
|
||||||
|
# initialize the parser object:
|
||||||
|
parser = optparse.OptionParser(
|
||||||
|
formatter=optparse.TitledHelpFormatter(width=78),
|
||||||
|
add_help_option=None)
|
||||||
|
|
||||||
|
# define options here:
|
||||||
|
parser.add_option( # customized description; put --help last
|
||||||
|
'-h', '--help', action='help',
|
||||||
|
help='Show this help message and exit.')
|
||||||
|
|
||||||
|
settings, args = parser.parse_args(argv)
|
||||||
|
|
||||||
|
# check number of arguments, verify values, etc.:
|
||||||
|
if args:
|
||||||
|
parser.error('program takes no command-line arguments; '
|
||||||
|
'"%s" ignored.' % (args,))
|
||||||
|
|
||||||
|
# further process settings & args if necessary
|
||||||
|
|
||||||
|
return settings, args
|
||||||
|
|
||||||
|
def main(argv=None):
|
||||||
|
settings, args = process_command_line(argv)
|
||||||
|
# application code here, like:
|
||||||
|
# run(settings, args)
|
||||||
|
return 0 # success
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
status = main()
|
||||||
|
sys.exit(status)
|
|
@ -0,0 +1,10 @@
|
||||||
|
def helloworld(ob):
|
||||||
|
print "Hello world"
|
||||||
|
return ob
|
||||||
|
|
||||||
|
@helloworld
|
||||||
|
def myfunc():
|
||||||
|
print "my function"
|
||||||
|
|
||||||
|
myfunc()
|
||||||
|
print myfunc
|
|
@ -0,0 +1,28 @@
|
||||||
|
class Turbo(object):
|
||||||
|
def turbo(self):
|
||||||
|
return "VRRRRROUUUMMM"
|
||||||
|
|
||||||
|
class Prix(object):
|
||||||
|
def get_prix(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
class Voiture(Prix, Turbo):
|
||||||
|
def __init__(self, constructeur, vitesse_max=160):
|
||||||
|
self.constructeur = constructeur
|
||||||
|
self.vitesse_max = vitesse_max
|
||||||
|
|
||||||
|
def roule(self):
|
||||||
|
return "vroummm"
|
||||||
|
|
||||||
|
def signaletique(self):
|
||||||
|
return "constructeur : {0}, vitesse_max {1}".format(self.constructeur,
|
||||||
|
self.vitesse_max)
|
||||||
|
|
||||||
|
class DoDoche(Voiture):
|
||||||
|
def get_prix(self):
|
||||||
|
return "4000"
|
||||||
|
|
||||||
|
def achete_voiture(voiture):
|
||||||
|
if not hasattr(voiture, "get_prix"):
|
||||||
|
raise TypeError("pas le bon type")
|
||||||
|
return "prix de la voiture: {0} euros".format(voiture.get_prix())
|
|
@ -0,0 +1,20 @@
|
||||||
|
liste = ['blah', 'blih', 'bluh']
|
||||||
|
iterateur = liste.__iter__()
|
||||||
|
print iterateur.next()
|
||||||
|
print iterateur.next()
|
||||||
|
print iterateur.next()
|
||||||
|
print iterateur.next()
|
||||||
|
#Traceback (most recent call last):
|
||||||
|
# File '<stdin>', line 1, in <module>;
|
||||||
|
#StopIteration
|
||||||
|
|
||||||
|
class Iterateur:
|
||||||
|
i = 0
|
||||||
|
def next(self):
|
||||||
|
if self.i <= 10: raise StopIteration
|
||||||
|
self.i += 1
|
||||||
|
return 2**self.i
|
||||||
|
def __iter__(self): return self
|
||||||
|
|
||||||
|
iterateur = Iterateur()
|
||||||
|
for i in iterateur: print i
|
|
@ -0,0 +1,18 @@
|
||||||
|
class NotFoundError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class MaClasse:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class MaClasseDeux:
|
||||||
|
pass
|
||||||
|
|
||||||
|
binding = dict(un=MaClasse, deux=MaClasseDeux)
|
||||||
|
|
||||||
|
def ma_factory(key):
|
||||||
|
if key in binding:
|
||||||
|
return binding[key]()
|
||||||
|
else:
|
||||||
|
return NotFoundError("keskece?")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Add auto-completion and a stored history file of commands to your Python
|
||||||
|
# interactive interpreter. Requires Python 2.0+, readline. Autocomplete is
|
||||||
|
# bound to the Esc key by default (you can change it - see readline docs).
|
||||||
|
#
|
||||||
|
# Store the file in ~/.pystartup, and set an environment variable to point to
|
||||||
|
# it, e.g. "export PYTHONSTARTUP=/max/home/itamar/.pystartup" in bash.
|
||||||
|
#
|
||||||
|
# Note that PYTHONSTARTUP does *not* expand "~", so you have to put in the full
|
||||||
|
# path to your home directory.
|
||||||
|
import rlcompleter
|
||||||
|
import readline
|
||||||
|
readline.parse_and_bind("tab: complete")
|
||||||
|
|
||||||
|
import os
|
||||||
|
histfile = os.path.join(os.environ["HOME"], ".pyhist")
|
||||||
|
try:
|
||||||
|
readline.read_history_file(histfile)
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
import atexit
|
||||||
|
atexit.register(readline.write_history_file, histfile)
|
||||||
|
del os, histfile
|
||||||
|
|
||||||
|
# enhanced completion
|
||||||
|
#import rlcompleter2
|
||||||
|
#rlcompleter2.setup()
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
class Sorter:
|
||||||
|
def sort(self, list):
|
||||||
|
for i in range(len(list) - 1):
|
||||||
|
for j in range(i, len(list)):
|
||||||
|
if self.compareItems(list[i], list[j]):
|
||||||
|
list[i], list[j] = list[j], list[i]
|
||||||
|
|
||||||
|
def getName(self):
|
||||||
|
return "Trieur de liste"
|
||||||
|
|
||||||
|
def getDescription(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def compareItems(self, item1, item2):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
class AscendantSorter(Sorter):
|
||||||
|
def compareItems(self, item1, item2):
|
||||||
|
return item1 >= item2
|
||||||
|
def getDescription(self):
|
||||||
|
return "Tri par ordre normal"
|
||||||
|
def getName(self):
|
||||||
|
return "Ascendant"
|
||||||
|
|
||||||
|
class DescendantSorter(Sorter):
|
||||||
|
def compareItems(self, item1, item2):
|
||||||
|
return item1 <= item2
|
||||||
|
def getDescription(self):
|
||||||
|
return "Tri par ordre inverse"
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
list = ['b', 'e', 'a', 'c', 'z']
|
||||||
|
s = AscendantSorter()
|
||||||
|
s.sort(list)
|
||||||
|
print list
|
||||||
|
s = DescendantSorter()
|
||||||
|
s.sort(list)
|
||||||
|
print list
|
|
@ -0,0 +1,10 @@
|
||||||
|
class Zone(object):
|
||||||
|
def __init__(self, name, level=0):
|
||||||
|
self.name = name
|
||||||
|
self.level = level
|
||||||
|
|
||||||
|
def __add__(self, other):
|
||||||
|
return Zone(self.name + other.name, level=self.level+other.level)
|
||||||
|
|
||||||
|
def __cmp__(self, other):
|
||||||
|
return cmp(self.level, other.level)
|
|
@ -0,0 +1,22 @@
|
||||||
|
class Wrap(object):
|
||||||
|
def __init__(self, name, wrap):
|
||||||
|
self.slots = ('_name', '_w')
|
||||||
|
self._name = name or "wrapped_element"
|
||||||
|
self._w = wrap
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
if name in self.slots:
|
||||||
|
return getattr(self, name)
|
||||||
|
else:
|
||||||
|
return getattr(self._w, name)
|
||||||
|
|
||||||
|
# def get_w(self, name):
|
||||||
|
# return getattr(self._w, name)
|
||||||
|
|
||||||
|
# def set_w(self, name, value):
|
||||||
|
# return setattr(self._w, name, value)
|
||||||
|
|
||||||
|
# _w = property (get_w, set_w)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "[W_Element %s]"% repr(self._name)
|
Loading…
Reference in New Issue