2013-01-08 11:15:45 +01:00
|
|
|
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**
|
|
|
|
|
2013-05-15 10:47:55 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
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``).
|
2013-01-08 11:15:45 +01:00
|
|
|
|
|
|
|
- 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é.
|
|
|
|
|
2013-05-15 10:47:55 +02:00
|
|
|
on peut alors créer des outils qui sauront traiter n'importe quel objet
|
|
|
|
pourvu qu'il respecte une ensemble d'interfaces.
|
2013-01-08 11:15:45 +01:00
|
|
|
|
2013-05-15 10:47:55 +02:00
|
|
|
.. todo:: travailler l'héritage, l'aggrégation, la délégation
|
2013-01-08 11:15:45 +01:00
|
|
|
|
|
|
|
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'
|
|
|
|
>>>
|
2013-05-15 10:47:55 +02:00
|
|
|
|
|
|
|
autre exemple : les méthodes statiques
|
|
|
|
|
|
|
|
>>> class A(object):
|
|
|
|
... @staticmethod
|
|
|
|
... def my_class_method(cls):
|
|
|
|
... # do stuff here
|
|
|
|
|
|
|
|
|