Programmation python courante¶
les espaces de nommage¶
L’espace de nommage le plus courant est l’organisation en modules et en packages.
Packages et modules:
package/
__init__.py
module1.py
subpackage/
__init__.py
module2.py
A utilser pour organiser votre projet
Permet de minimiser les risques de conflits de nome
Permet de diminuer les entrées dans le PYTHONPATH
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 *
lance un module en tant que script :
if __name__ == "__main__":
main()
Organisation modulaire
- construire des composants élémentaires
- combiner ces composants
- utiliser une structure pyramidale : les composants sont les éléments de composants plus complexes.
- 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)
modules chargés et modules importés¶
Les modules susceptibles d’être chargés sont dans le PYTHONPATH
.
Mais comment peut-on savoir ou ils sont physiquement (sur le disque dur) ?
-
`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'>
>>>
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 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
>>>
Pour récupérer le chemin du module
print(os.path.abspath(<module>.__file__))
Pour importer un module qui n’est pas dans le sys.path
fch = open('/path/to/mymodule/custom.py', 'r')
my_module = imp.load_module('dhcp_custom', fch, '/path/to/mymodule.py', ('.py', 'U', 1))
Connaître la version d’un module¶
Exemple : le module datetime
C’est suivant la version de python car c’est la librairie standard.
Sinon, en général il y a un attribut __version__
>>> import sqlalchemy
>>> sqlalchemy.__version__
'0.9.8'
>>>
Les méthodes spéciales¶
méthodes spéciales correspondants aux interfaces des types de bases :
-
__init__
(self, *args, **kwargs)¶ -
le constructeur de l'instance d'objet
-
__add__
(self, other)¶ correspond à la notation +
exemple :
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)
>>> 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'
les attributs ne sont pas systématiquement encapsulées en python.
pour contrôler l’accès aux attributs, on utilise les méthodes spéciales:
__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'
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é.
>>> 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