2013-01-08 11:15:45 +01:00
|
|
|
Programmation python courante
|
|
|
|
================================
|
|
|
|
|
|
|
|
.. _namespaces:
|
|
|
|
|
2013-05-15 10:47:55 +02:00
|
|
|
les espaces de nommage
|
2013-01-08 11:15:45 +01:00
|
|
|
-----------------------
|
|
|
|
|
2015-05-05 15:00:47 +02:00
|
|
|
L'espace de nommage le plus courant est l'organisation en modules et en packages.
|
|
|
|
|
2013-01-08 11:15:45 +01:00
|
|
|
Packages et modules::
|
|
|
|
|
|
|
|
package/
|
|
|
|
__init__.py
|
|
|
|
module1.py
|
|
|
|
subpackage/
|
|
|
|
__init__.py
|
|
|
|
module2.py
|
|
|
|
|
2013-05-15 10:47:55 +02:00
|
|
|
A utilser pour organiser votre projet
|
|
|
|
Permet de minimiser les risques de conflits de nome
|
|
|
|
Permet de diminuer les entrées dans le :envvar:`PYTHONPATH`
|
2013-01-08 11:15:45 +01:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
import package.module1
|
|
|
|
from package.subpackage import module2
|
|
|
|
from package.subpackage.module2 import name
|
|
|
|
|
|
|
|
- le fichier `__init__.py`
|
|
|
|
- `reload(module)` au prompt
|
|
|
|
|
|
|
|
- dangereux : l'import "*", utiliser l'attribut spécial `__all__` pour l'import
|
|
|
|
sélectif
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
from os import *
|
|
|
|
|
2013-05-15 10:47:55 +02:00
|
|
|
lance un module en tant que script :
|
2013-01-08 11:15:45 +01:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|
|
|
|
|
2013-05-15 10:47:55 +02:00
|
|
|
Organisation modulaire
|
2013-01-08 11:15:45 +01:00
|
|
|
|
2013-05-15 10:47:55 +02:00
|
|
|
- construire des composants élémentaires
|
|
|
|
- combiner ces composants
|
2013-01-08 11:15:45 +01:00
|
|
|
- utiliser une structure pyramidale : les composants sont les éléments de
|
|
|
|
composants plus complexes.
|
|
|
|
|
|
|
|
|
2013-05-15 10:47:55 +02:00
|
|
|
- découplage de l'ensemble en composants indépendants (gros programmes réalisables)
|
|
|
|
- donner de la structure (rendre les gros programmes compréhensibles)
|
|
|
|
- spécifier les liens entre les composants (rendre les programmes maintenables)
|
|
|
|
- identifier les sous-composants indépendants (rendre les programmes réutilisables)
|
|
|
|
- forcer l'abstraction (augmenter la sureté du programme)
|
2013-01-08 11:15:45 +01:00
|
|
|
|
2017-06-21 10:52:29 +02:00
|
|
|
modules chargés et modules importés
|
2015-05-05 15:00:47 +02:00
|
|
|
--------------------------------------
|
|
|
|
|
2015-05-13 15:37:00 +02:00
|
|
|
Les modules susceptibles d'être chargés sont dans le :envvar:`PYTHONPATH`.
|
2017-06-21 10:52:29 +02:00
|
|
|
Mais comment peut-on savoir ou ils sont physiquement (sur le disque dur) ?
|
2015-05-05 15:00:47 +02:00
|
|
|
|
|
|
|
.. envvar:: `sys.modules`
|
|
|
|
|
|
|
|
>>> 'twisted' in sys.modules
|
|
|
|
False
|
|
|
|
>>> import twisted
|
|
|
|
>>> 'twisted' in sys.modules
|
|
|
|
True
|
|
|
|
>>> sys.modules['twisted']
|
|
|
|
<module 'twisted' from '/usr/lib/python2.7/dist-packages/twisted/__init__.pyc'>
|
2017-06-21 10:52:29 +02:00
|
|
|
>>>
|
2015-05-05 15:00:47 +02:00
|
|
|
|
2017-06-21 10:52:29 +02:00
|
|
|
.. attention:: un module présent dans `sys.modules` n'est pas forcément importé
|
|
|
|
dans l'espace de nommage usuel. Il faut importer le module pour
|
2015-05-05 15:00:47 +02:00
|
|
|
pouvoir l'utiliser.
|
|
|
|
|
|
|
|
>>> sys.modules['email']
|
|
|
|
<module 'email' from '/usr/lib/python2.7/email/__init__.pyc'>
|
|
|
|
>>> dir(email)
|
|
|
|
Traceback (most recent call last):
|
|
|
|
File "<stdin>", line 1, in <module>
|
|
|
|
NameError: name 'email' is not defined
|
2017-06-21 10:52:29 +02:00
|
|
|
>>>
|
|
|
|
|
|
|
|
Pour récupérer le chemin du module
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
print(os.path.abspath(<module>.__file__))
|
|
|
|
|
|
|
|
Pour importer un module qui n'est pas dans le `sys.path`
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
|
|
|
|
fch = open('/path/to/mymodule/custom.py', 'r')
|
|
|
|
my_module = imp.load_module('dhcp_custom', fch, '/path/to/mymodule.py', ('.py', 'U', 1))
|
2015-05-05 15:00:47 +02:00
|
|
|
|
|
|
|
Connaître la version d'un module
|
|
|
|
-------------------------------------
|
|
|
|
|
|
|
|
Exemple : le module ``datetime``
|
|
|
|
|
2017-06-21 10:52:29 +02:00
|
|
|
C'est suivant la version de python car c'est la librairie standard.
|
2015-05-05 15:00:47 +02:00
|
|
|
|
2017-06-21 10:52:29 +02:00
|
|
|
Sinon, en général il y a un attribut __version__
|
2015-05-05 15:00:47 +02:00
|
|
|
|
|
|
|
>>> import sqlalchemy
|
|
|
|
>>> sqlalchemy.__version__
|
|
|
|
'0.9.8'
|
2017-06-21 10:52:29 +02:00
|
|
|
>>>
|
2015-05-05 15:00:47 +02:00
|
|
|
|
|
|
|
|
2013-01-08 11:15:45 +01:00
|
|
|
Les méthodes spéciales
|
|
|
|
-----------------------
|
|
|
|
|
2013-05-15 10:47:55 +02:00
|
|
|
méthodes spéciales correspondants aux interfaces des types de bases :
|
2013-01-08 11:15:45 +01:00
|
|
|
|
|
|
|
.. function:: __init__(self, *args, **kwargs)
|
|
|
|
le constructeur de l'instance d'objet
|
|
|
|
|
|
|
|
.. function:: __add__(self, other)
|
|
|
|
|
|
|
|
correspond à la notation `+`
|
|
|
|
|
|
|
|
exemple :
|
|
|
|
|
|
|
|
.. literalinclude:: snippets/specialmethods.py
|
|
|
|
|
|
|
|
>>> from specialmethods import *
|
|
|
|
>>> z = Zone("titi", 10)
|
|
|
|
>>> z2 = Zone("tutu", 40)
|
|
|
|
>>> z > z2
|
|
|
|
False
|
|
|
|
>>> z + z2
|
|
|
|
<specialmethods.Zone object at 0x7f02d95fb190>
|
|
|
|
>>> z3 = z + z2
|
|
|
|
>>> z3.name
|
|
|
|
'tititutu'
|
|
|
|
>>> z3.level
|
|
|
|
50
|
|
|
|
>>>
|
|
|
|
|
|
|
|
Attributs et accesseurs
|
|
|
|
---------------------------
|
|
|
|
|
|
|
|
python est un langage à attributs, c'est-à-dire que le protocole d'accès
|
|
|
|
aux attributs est règlable.
|
|
|
|
|
|
|
|
>>> class C(object):
|
|
|
|
... classattr = "a class attribute"
|
|
|
|
...
|
|
|
|
>>> cobj = C()
|
|
|
|
>>> cobj.classattr
|
|
|
|
'a class attribute'
|
|
|
|
>>> cobj.insattr = "an instance attribute"
|
|
|
|
>>> cobj.insattr
|
|
|
|
'an instance attribute'
|
|
|
|
>>> C.__dict__['classattr']
|
|
|
|
'a class attribute'
|
|
|
|
>>> cobj.__dict__['insattr']
|
|
|
|
'an instance attribute'
|
|
|
|
|
2013-05-15 10:47:55 +02:00
|
|
|
les attributs ne sont pas systématiquement encapsulées en python.
|
2013-01-08 11:15:45 +01:00
|
|
|
|
2013-05-15 10:47:55 +02:00
|
|
|
pour contrôler l'accès aux attributs, on utilise les méthodes spéciales::
|
2013-01-08 11:15:45 +01:00
|
|
|
|
|
|
|
__getattr__(self, name)
|
|
|
|
|
|
|
|
__setattr__(self, name, value)
|
|
|
|
|
|
|
|
class AnObject(object):
|
|
|
|
......
|
|
|
|
def __setattr__(self, name, val):
|
|
|
|
if name == 'src': #do something
|
|
|
|
# this will assign the real object.name,
|
|
|
|
#despite __setattr__
|
|
|
|
self.__dict__[name]=val
|
|
|
|
def __getattr__(self, name):
|
|
|
|
# ...
|
|
|
|
try:
|
|
|
|
func = getattr(obj, "method")
|
|
|
|
except AttributeError:
|
|
|
|
... deal with missing method ...
|
|
|
|
else:
|
|
|
|
result = func(args)
|
|
|
|
|
|
|
|
func = getattr(obj, "method", None)
|
|
|
|
if callable(func):
|
|
|
|
func(args)
|
|
|
|
|
|
|
|
- un **attribut** spécial : `__slots__`
|
|
|
|
|
|
|
|
permet de fixer les attributs possibles d'une classe
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
>>> class Bar(object):
|
|
|
|
... __slots__ = ("a","b","c")
|
|
|
|
...
|
|
|
|
>>> b = Bar()
|
|
|
|
>>> b.a = "toto"
|
|
|
|
>>> b.a
|
|
|
|
'toto'
|
|
|
|
>>> b.d = "titi"
|
|
|
|
Traceback (most recent call last):
|
|
|
|
File "<stdin>", line 1, in ?
|
|
|
|
AttributeError: 'Bar' object has no attribute 'd'
|
|
|
|
|
2013-05-15 10:47:55 +02:00
|
|
|
les slots
|
|
|
|
~~~~~~~~~~~
|
|
|
|
|
|
|
|
.. important:: l'encapsulation n'est pas une condition de base de la programmation
|
|
|
|
par objects, surtout que le contrôle nuit à l'agilité.
|
|
|
|
|
2013-01-08 11:15:45 +01:00
|
|
|
>>> class Point(object):
|
|
|
|
... __slots__ = 'x', 'y'
|
|
|
|
...
|
|
|
|
>>> p = Point()
|
|
|
|
>>> p.x = 2
|
|
|
|
>>> p.y = 3
|
|
|
|
>>> p.z = 4
|
|
|
|
Traceback (most recent call last):
|
|
|
|
File "<stdin>", line 1, in <module>
|
|
|
|
AttributeError: 'Point' object has no attribute 'z'
|
|
|
|
>>>
|
|
|
|
|
|
|
|
- notation `|` et notation `>`
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
class Test:
|
|
|
|
nombre = 1
|
|
|
|
def __or__(self, other):
|
|
|
|
return self.nombre + other.nombre
|
|
|
|
|
|
|
|
def __lshift__(self, other):
|
|
|
|
self.nombre = self.nombre + other.nombre
|
|
|
|
|
|
|
|
t1 = Test()
|
|
|
|
t2 = Test()
|
|
|
|
t2.nombre = 2
|
|
|
|
print t1 | t2
|
|
|
|
t1 << t2
|
|
|
|
print t1.nombre
|