[python sur hébérgement mutualisé ovh ] [programmation objet avec Python] [des liens utiles sur python]
Programmation orientée objet et les modules avec Python
Fabrice de Caluwe
Voici un survol des principales informations à retenir pour développer vos objets à l'aide de Python et intégrer vos propres modules.
cette page n'est pas exhaustive. Sachant qu'avec Python, tout est plus ou moins un objet... Il y aurait beaucoup à dire sur la programmatioin orientée objet. La finalité de cette page est plus de rassembler les informations indispensables et les petites astuces ... en français !
1- Définition d'une classe
Définition d'une classe qu'on appellera "test". Le mot clé "class" est suivi du nom à donner, une paire de parenthèse suivie de deux points.
Attention à respecter l'indentation propre à Python
exemple de définition
class test(object):
"classe test. Ma ligne commentaire"
|
exemple d'appel dans le programme
mon_objet = test()
#appel de la ligne de commentaire définie dans une classe
print(mon_objet.__doc__)
|
1- La première ligne comporte un commentaire. Il est facultatif mais vraiment conseillé car il pourra ensuite être appelé par la méthode __doc__ (voir plus bas).
2- Si la classe ne dérive d'aucun objet ancêtre, le mot clé "object" doit être stipulé. Si la classe dérive d'un objet déjà défini, indiquez le nom de cet objet (ancêtre) à la place du mot clé "object".
Avec Python il est possible de spécifier plusieurs ancêtres les uns séparés des autres par une virgule.
Attention: Si votre classe hérite d'un objet ancêtre, il est nécessaire d'appeler sa méthode __init__ (constructeur coir cette page un peu plus bas).
Public ou privé ?
Toute classe est "public" à moins que vous fassiez précéder son nom par le caractère underscore _
Il n'y a pas de mot clé "private" ou "public" avec Python.
D'une manière générale, toute fonction, attribut, méthode de classe sera privé à partir du moment ou le nom que vous avez choisi commence par le caractère de soulignement.
exemple de définition d'une classe privée
class _test(object):
"classe test. Ma ligne commentaire"
|
Une classe ou une fonction vide : le mot clé Pyhton pass
Parfois, il est utile de définir une classe ou une fonction mais sans instructions. Ce qui revient dans d'autres langages à ouvrir puis fermé les accolades. Or à cause de l'identation, cela n'est pas pas possible en Python. Cette fameuse paire d'accolade en ouverture fermeture peut être remplacée par le mot clé pass
def ma_fonction():
pass
#équivalent dans les langages à accolades :
function ma_fonction()
{
#aucune instruction
}
|
2- Méthode constructeur
La méthode constructeur __init__() est exécutée automatiquement lorsque l'on instancie un nouvel objet. Elle permet d'initialiser les attributs. Le mot clé "self" signifie que l'on fait référence à l'objet lui-même. Lorsque vous appelerez l'objet, vous pourrez au même moment définir les variables "v1" et "v2". Si vous ne les définissez pas, les attributs V1 et V2 recevront la valeur que vous avez définie par défaut.
exemple de constructeur
class test(object):
"classe test. Ma ligne commentaire"
def __init__(self, v1='truc',v2=56):
self.v1 = v1
self.v2 = v2
#pour appeler la méthode plusieurs solutions
#on laisse la valeur par défaut des attributs
mon_objet = test()
#on indique la valeur des attributs #remarquez que l'on ignore l'argument self quand on appelle la méthode
mon_objet = test('hello',10)
#on indique seulement un ou plusieurs valeurs
#le reste étant défini par défaut
mon_objet = test(v2=56)
|
Attention aux objets encêtres que vous appelez à l'intérieur de votre classe !
Vu de l'exterieur, c'est à dire depuis le programme appelant, vous avez remarqué que l'argument self a été ignoré. ce n'est pas une erreur. Mais si vous faites appelle à une méthode de classe encêtre à l'intérieur de votre classe, il faut spécifier l'argument self !
Lorsqu'une classe hérite d'une classe encêtre, il est obligatoire d'appeler le constructeur de la classe encêtre dans la classe enfant si cette classe enfant utilise elle-même un constructeur.
En clair, si votre classe dérive d'un autre objet et qu'elle comporte une méthode __init__ vous devez également appeler la méthode __init_ de l'objet de référence.
exemple de d'appel constructeur de la classe encêtre
class test(objet_encetre):
"classe test. Ma ligne commentaire"
def __init__(self, v1='truc',v2=56):#initialisation de la classe test
objet_encetre.__init__(self ) #initialisation de l'encêtre
self.v1 = v1
self.v2 = v2
|
3- Définition d'une méthode
Définir une méthode consiste à créer une fonction à l'intérieur de la classe qui doit toujours comporter un paramètre qui est une référence à l'instance à la différence d'une fonction). Par défaut, le paramètre sera "self".
exemple
class test(object):
"classe test. Ma ligne commentaire"
def __init__(self):
self.ma_variable = 1
def ma_methode(self):
print 'cette méthode ne sert à rien mais ca fonctionne'
|
4- Portée des variables ou espace de noms
A l'intérieur d'une fonction, les variables sont locales. Elles ne peuvent pas être appelées directement par le programme. C'est aussi le cas à l'intérieur d'une méthode.
Il existe donc une hierarchie dans laquelle il faut se demander dans quel contexte s'exécute une variable. Est ce dans la méthode (ou la fonction) en cours, dans la classe ou dans le programme principale ?
La lecture des variables définies à l'extérieur est possible mais pas l'écriture à moins d'utiliser le mot clé "global".
Un exemple vaut mieux qu'un long discours incompréhensible ;-)
exemple
# définition d'une classe
# définition de 3 variables de même nom
#mais comportant chacune 1 valeur différente
class maclasse(object):
ma_variable = 'B' # déclaration au niveau de maclasse
def ma_methode(self):
print (ma_variable,self.ma_variable,maclasse.ma_variable)
ma_variable = 'A' #déclaration à l'extérieur de la classe
mon_objet = maclasse()
mon_objet.ma_variable = 'C' #déclaration pour ma_methode()
mon_objet.ma_methode()
# résultat:
A,C,B
|
4- Enregistrement en tant que module
Il est pratique de regrouper une ou plusieurs classes dans un fichier séparé. Dans ce cas, le programme principal peut appeler votre fichier comme un module.
Pour cela le fichier contenant votre classe doit être enregistrée dans un fichier comportant l'extension "py". Le nom du module sera le nom du fichier.
Où enregistrer le module ainsi créé ?
Lorsque vous importez un module, Python va le rechercher dans différentes arborescences jusqu'à le trouver ( de manière analogue à un PATH sous dos ou linux). Pour connaître les différents chemins dans lesquels votre Python va effectuer ses recherches, vous pouvez utiliser les commandes suivantes :
import sys
sys.path
#ou print sys.path si vous êtes sur une page web
|
Si le chemin dans lequel vous avez placé le module à importer ne figure pas dans le path, vous pouvez l'ajouter ainsi :
import sys
sys.path.append('/home/utilisateur') |
Remarque : si le répertoire /home/utilisateur figure dans le path, Python recherchera recursivement dans les sous répertoires.
Comment importer un module dans un programme principal ?
Il existe deux grandes méthodes d'importation qui n'ont pas les mêmes conséquences au niveau du programme principal. La différence essentiel porte sur l'espace de nom.
1- import mon_module
Les classes, les attributs sont séparés d'avec l'espace de nom de votre programme principal. En d'autre terme, les noms que vous avez choisi pour vos fonctions, classes dans le module etc... ne rentreront pas en conflit avec le programme appelant tout simplement parce que votre module sera considéré comme un objet lui -même. Ainsi si votre module mon_module comporte une classe nommée ma_classe, un appel depuis le programme principal se fera par mon_module.ma_classe
exemple avec import
#si le nom du fichier est test.py il faudra écrire:
import test
mon_objet = test.ma_classe() |
2- from mon_module import [nom de la classe ou * pour tout importer]
Les classes, les attributs importés rentrent directement dans l'espace de noms de votre programme principal. Cela est très pratique pour faire des appels plus directs au niveau de la syntaxe mais cela peut être une source de conflit. C'est pourquoi il est possible de restreindre l'importation en jouant sur la syntaxe. En effet, autant le jocker * permet de tout importer, autant on peut limiter les classes ou les fonctions à importer en les nommant explicitement
exemple avec from import
#si le nom du fichier est test.py il faudra écrire:
#caractères jocker, on importe tout
from test import *
mon_objet = ma_classe()
#on restreint l'importation aux éléments à importer
from test import ma_classe1,ma_classe9
mon_objet = ma_classe() |
Quoi choisir ?
Quelques astuces personnelles...
Pour commencer, si le module contient beaucoup d'informations, il sera judicieux de limiter l'importation pour gagner en ressource. Pas la peine de tout prendre si on ne se sert que d'une chose.
Si le programme principal est assez court, on sera content de pouvoir partager l'espace de nom avec le module.
Si vous connaissez mal le module car vous ne l'avez pas développé, le fait de ne pas partager l'espace de nom permettra d'éviter des conflits...
Remarque: quand il est importé, le __name__ du module créé est le nom du fichier sans l'extension.
Comment vérifier si le module est chargé au moment de l'exécution du programme principal ?
Parmi les astuces permettant de détecter si un module a bien été chargé, on peut utiliser un bloc de gestion d'exception.
L'avantage est de pouvoir gérer le comportement du programme en cas d'erreur et d'éviter que Python ne déclenche lui-même une exception.
Sur les exceptions, il y a beaucoup à écrire et ce n'est pas la finalité de cette page. Il y a une page assez clair consacrée aux exceptions sur le site développez que vous pouvez consulter en cliquant ici.
try:
import mon_module
except:
print('impossible de charger le module')
|
Comment savoir si le module est chargé en tant que module ou en tant que programme principal ?
Il sera alors peut être utile de spécifier un comportement particulier du programme en fonction de la manière dont il est appelé.
A priori votre module ne sera appelé que depuis un programme principal sans lequel il ne peut fonctionner. Mais il eut aussi être appelé directement.
Une petite instruction très utile en bas de votre module vous permettra de déterminer un comportement spécifque en fonction du type d'appel (direct ou importation) exemple
#si l'appel est direct
if __name__ == "__main__":
print ("vous ne pouvez pas appeler directement ce fichier car c'est une bibliothèque")
|
|