[Design Pattern] Singleton et Multiton en Python

15 janvier 2008, 3 Commentaires »

Pour le développement de Pyxoo je suis souvent confronté à la création de classes qui ne doivent proposer qu’une seule instance d’elles-même. La solution du Singleton semble bien évidemment la plus pertinente pour répondre à ce problème.

Malgré les différentes solutions trouvées sur la toile ici ou , un problème persiste en python : il est impossible de rendre privé un contructeur de classe comme en java.

Pour celà, un petit hack existe :

class MaClasse:
    __instance = None
    class __PRIVATE:pass

    @classmethod
    def getInstance(cls):
        if cls.__instance is None: cls.__instance = MaClasse(cls.__PRIVATE)
        return cls.__instance

    def __init__(self, privateAccess):
        if privateAccess is not self.__PRIVATE:
            raise Exception(“Contructeur privé”)

#Pour recuperer l’instance de la classe :
o = MaClasse.getInstance()

Nous venons de voir une manière simple de rendre privé le constructeur d’une classe et donc par la même occasion le design pattern Singleton qui, je le rappelle, fait partie de la famille “Création”.

Un avantage de cette méthode est la méthode statique getInstance() qui permet au premier coup d’oeil de comprendre qu’il s’agit d’un Singleton.

Un autre motif de conception peu connu mais néanmoins utile : le Multiton. Ce dernier est une sorte de singleton mais associé à une clé passée en paramètre de la méthode getInstance().

Un exemple concret de multiton est le ModelLocator implémenté dans la librairie Pyxoo. Un ModelLocator est associé à un Plugin passé en paramètre.

Voici un autre exemple d’implémentation du design pattern Multiton :

class MaClasse:
    __instances = dict()
    class __PRIVATE:pass

    @classmethod
    def getInstance(cls, unObjet):
        if unObject not in cls.__instances:
            cls.__instances[unObjet] = MaClasse(cls.__PRIVATE)
        return cls.__instances[unObjet]

    def __init__(self, privateAccess):
        if privateAccess is not self.__PRIVATE:
            raise Exception(“Contructeur privé”)

#Pour recuperer une instance de la classe

o1 = MaClasse.getInstance( “A1″ )
o2 = MaClasse.getInstance( “A1″ )
o3 = MaClasse.getInstance( “A2″ )

id(o1) == id(o2) #retourne vrai
id(o1) == id(o3) #retourne faux
 

Une méthode statique release() peut souvent être utile dans les deux cas présentés ci-dessus. En effet, il peut être nécessaire de réinitialiser l’instance.

class MaClasse:
    __instance = None
    class __PRIVATE:pass

    @classmethod
    def getInstance(cls):
        if cls.__instance is None:cls.__instance = MaClasse(cls.__PRIVATE)
        return cls.__instance

    def __init__(self, privateAccess):
        if privateAccess is not self.__PRIVATE:
            raise Exception( “Constructeur privé”)

    @classmethod
    def release(cls):
        cls.__instance = None

Comme vous pouvez le constater cette méthode réinitialise l’instance de la classe.

Voilà, c’est fini pour ce petit tutoriel, en espérant vous avoir été utile dans la compréhension de ces deux Design Pattern. :)

[Pyxoo] Librairie Python - Revision 2

11 août 2007, Aucun commentaire »

Aujourd’hui sort la seconde révision de Pyxoo, un framework développé en Python, qui est un portage de la librairie Pixlib.

Pour cette seconde révision, j’ai pu mettre en place le package de log :

  • LogEvent
  • ILogListener
  • Logger
  • LogLevel
  • PyxooDebugChannel
  • PyxooDebug
  • Stringifier
  • BasicStringifier
  • PyxooStringifier

Comme vous l’aurez sûrement compris, ce package propose un ensemble de classes permettant de logger et debugger. Tout ce là utilisant le système d’évènements typés et son EventBroadcaster proposé lors de la première révision de Pyxoo.
A l’image de ce que l’on peut retrouver en Java (Log4J), on retrouve le gestion de log par niveau : DEBUG, INFO, WARN, ERROR, FATAL.

Je vous rappelle l’adresse permettant de récupérer les sources via SVN : http://svn.pyxoo.skitoo.org/trunk/

Comme toujours n’hésitez pas à faire un petit tour sur le groupe Pyxoo pour faire partagés vos expériences, critiques et découvertes de bugs.

[Pyxoo] Petit exemple rapide d’utilisation de la classe EventBroadcaster

30 juillet 2007, 2 Commentaires »

Afin de compléter mon précédent billet concernant Pyxoo je vous livre ici un premier exemple concernant l’utilisation de la classe EventBroadcaster.

from Pyxoo.events.broadcaster import EventBroadcaster
from Pyxoo.events.event import StringEvent
import sys

# création de listeners proposant une méthode onLog

class LogListener:
def onLog(self, event):
raise NotImplementedError

class TextFileLogger(LogListener):
def __init__(self):
self.__file = open(“mylogs.log”, “w+”)
def onLog(self, event):
self.__file.write(event.getString()+\n)

class StdOutLogger(LogListener):
def onLog(self, event):
sys.stdout.write(event.getString()+\n)

log1 = TextFileLogger()
log2 = StdOutLogger()
EVENT_TYPE = “onLog”

eventBroadcaster = EventBroadcaster()
# on ajoute un listener associé à un type d’événement
# dans l’eventBroadcaster
eventBroadcaster.addEventListener( EVENT_TYPE, log1 )
eventBroadcaster.addEventListener( EVENT_TYPE, log2 )

# création d’un événement avec pour eventType "onLog"
event1 = StringEvent( EVENT_TYPE, “Bonjour” )
event2 = StringEvent( EVENT_TYPE, “Au revoir” )

# diffusion de l’événement. Tous les listeners associés
# à l’événement "onLog" reçoivent l’événement et le traitent.
eventBroadcaster.broadcastEvent( event1 )
eventBroadcaster.broadcastEvent( event2 )

Bien sûr ce n’est qu’un exemple très simple de l’utilisation de la classe. On peut imaginer de nombreux types d’utilisation dans des contextes différents : gestion des événements d’une application Pygame, d’événements provenant d’une socket, etc…

[Pyxoo] Librairie Python - Revision 1

29 juillet 2007, 2 Commentaires »

Ca y est je me lance !
Suite à une première étude du framework PixLib développé par un collègue Francis Bourre, j’ai décidé de me lancer dans le portage en Python de celui-ci. Le nom du projet : Pyxoo

Pour cette première révision je me suis penché sur le package Events du frameworks, c’est à dire toute la partie du système d’EventBroadcaster, d’évenements typés, du ChannelBroadcaster et de l’ApplicationBroadcaster.
Pour me faciliter la tâche dans la vérification des types de données, j’ai mis en place un petit module utils contenant une classe Type proposant une suite de méthodes statiques permettant de vérifier les types de valeurs.
Je tiens à préciser que Pyxoo est distribué sous Mozilla Public License Version 1.1

Pour le moment les sources sont seulement récupérable via SVN :

svn checkout http://svn.pyxoo.skitoo.org/trunk/ pyxoo

Normalement un Trac devrait voir le jour d’ici peu.

Afin d’avoir des retours utilisateurs sur Pyxoo j’ai mis en place un groupe sur Google http://groups.google.fr/group/pyxoo. N’hésitez pas à faire partager vos expériences, critiques et découvertes de bugs via ce groupe.

[Django] Vidéo de Django aux Journées Python Francophones 2007

17 juillet 2007, Aucun commentaire »

Un billet qui arrive vraiment en retard étant donné que la vidéo de cette conférence est disponible depuis le 19 juin 2007 sur le site de l’AFPY. Sur cette vidéo vous pourrez découvrir ou redécouvrir la conférence de David Larlet concernant Django.
La vidéo est en deux parties : la première de 5 minutes et la seconde de 35 minutes.

La première partie de la vidéo :



La deuxième partie de la vidéo :

[Django] Ouverture du site francophone Django !

3 juin 2007, Aucun commentaire »

Depuis ce week-end, la communauté francophone du framework Django a enfin son site. Tout cela grâce au travail des contributeurs. Pour le moment se trouvent présents sur le site un guide d’installation du framework ainsi qu’un tutoriel qui permet de faire ses premiers pas dans le fabuleux monde de Django. :)

[Python] Journée Python Francophone 2007

29 mai 2007, Aucun commentaire »

Journée python 2007

Se tiendra ce week-end, le 2 et 3 juin, à la Cité des Sciences à Paris la première journée python francophone organisée par l’afpy. On y retrouvera entre autres une présentation sur le framework Django réalisée par David Larlet.
De nombreux autres sujets seront proposés : Zope, Twisted, Python et la 3D, etc…
Le programme complet du week-end.

[Design Patterns] Et si on parlait Stratégie ?

17 mai 2007, 11 Commentaires »

Aujourd’hui je vais tenter de vous expliquer comment fonctionne l’un des Design Patterns les plus utilisé qui fut initialement proposé par le GOF (Gang Of Four) : le Design Pattern Stratégie.

Pour commencer, il peut être intéressant de rappeler ce que sont les Design Pattern ou “Motifs de conception” en français. Les Design Patterns sont un ensemble de solutions standards permettant de répondre à des problèmes de conception rencontrés lors du développement de projets orientés objet. Les Design Patterns se regroupent dans trois grands groupes : Créationnel, Structurel et Comportemental. Le motif de conception que l’on va voir aujourd’hui fait partie du dernier groupe : les comportementaux.

Le Design Pattern Stratégie

Description :

L’intérêt principal de ce motif de conception est de permettre l’encapsulation d’algorithmes et de les rendre permutables. En effet, imaginons que l’on souhaite changer dynamiquement le comportement d’un objet et cela sans modifier la classe de ce dernier. A première vue, celà semble plutôt compliqué… mais il n’en est rien :)
Prenons un exemple simple : Une classe Personne qui a le dont de se déplacer. On peut imaginer plusieurs types de déplacements : marcher, courir !
De manière générale on aurait tendance à créer une méthode par déplacement :

Exemple en Python:

class Personne:
def marcher(self):
print “je marche”

def courir(self):
print “je cours”

Exemple en PHP 5 :

class Personne
{
public function marcher()
{
print “je marche”;
}

public function courir()
{
print “je cours”;
}
}

C’est pas mal, mais rien de très dynamique ! En effet, imaginons que l’on souhaite ajouter un nouveau comportement de déplacement (par exemple : nager) il faudra ajouter une nouvelle méthode.
Stratégie va permettre à notre classe Personne de posséder un comportement de déplacement dynamiquement interchangeable. Pour cela nous devons externaliser les comportements de la classe en utilisant un système bien connu en POO : la composition.
Regardons le diagramme de classe suivant :

Le diagramme UML :

Design pattern Stratégie

Ce schéma mérite une petite explication. Comme on peut le voir, la classe Personne ne possède plus les trois méthodes “marcher“, “courir” mais elles ont été remplacées par deux autres : “setMouvement” et “déplacer“. La première va nous permettre d’attribuer aux instances de la classe Personne un objet Mouvement. La seconde quant à elle va exécuter le mouvement précédemment attribué à l’objet Personne. Les comportements sont désormais des classes à part entière qui implémente l’interface Mouvement.

Exemple en python :

class Personne:
def __init__(self):
self.__mouvement = None

def setMouvement(self, mouvement):
self.__mouvement = mouvement

def deplacer(self):
if self.__mouvement:
self.__mouvement.execute()

class Mouvement:
def execute(self):
raise “Doit être implementé”

class Marcher(Mouvement):
def execute(self):
print “je marche”

class Courir(Mouvement):
def execute(self):
print “je cours”

pers = Personne()

unMouvement = Marcher()
pers.setMouvement( unMouvement )
pers.deplacer() #affiche "je marche"

unMouvement = Courir()
pers.setMouvement( unMouvement )
pers.deplacer() #affiche "je cours"
 

En Python la notion d’interface comme en Java ou PHP 5 n’existe pas. J’ai donc fait en sorte, dans mon exemple, que la méthode execute de la classe Mouvement soit obligatoirement redéfinie dans les classes qui étendent de celle-ci.

Exemple en PHP 5 :

interface Mouvement
{
public function execute();
}

class Marcher implements Mouvement
{
public function execute()
{
print “je marche”;
}
}

class Courir implements Mouvement
{
public function execute()
{
print “je cours”;
}
}

class Personne
{
private $mouvement;

public function setMouvement( Mouvement $mouvement )
{
$this->mouvement = $mouvement;
}

public function deplacer()
{
if( !is_null($this->mouvement) )
{
$this->mouvement->execute();
}
}
}

$pers = new Personne();

$unMouvement = new Marcher();
$pers->setMouvement( $unMouvement );
$pers->deplacer();// affiche "je marche"

$unMouvement = new Courir();
$pers->setMouvement( $unMouvement );
$pers->deplacer();// affiche "je cours"
 

La méthode deplacer appelle la méthode execute du mouvement passé en paramètre. On s’aperçoit dans cet exemple que comportement de la méthode deplacer est modifiable dynamiquement. Lors de son premier appel elle affiche “je marche” puis “je cours” lors du second appel. Ceci est du au fait que le mouvement passé en paramètre n’est plus le même. Imaginons désormais que l’on doivent ajouter un nouveau comportement de déplacement (par exemple : “nager”), il suffira tout simplement de créer une nouvelle classe nommée Nager qui implémente la classe Mouvement.

class Nager(Mouvement):
def execute(self):
print “je nage”

pers = Personne()

unMouvement = Nager()
pers.setMouvement( unMouvement )
pers.deplacer() #affiche "je nage"
 

Très pratique si votre boss ne vous à fourni que la version compilée de la classe Personne :) On peut modifier son comportement sans toucher une seule ligne de celle-ci.

Et voilà que ce premier tutoriel sur les Design Patterns touche à sa fin. En espérant que ça vous a plu… :)

[Benchmark] Appel de fonctions : PHP vs Python

19 février 2007, 2 Commentaires »

Aujourd’hui nous allons voir un petit test de performance sur des appels de fonctions récursifs grâce à la suite de Fibonacci dans deux langages distincts : le PHP et le Python.
Ce test a été réalisé sur la machine suivante :
Intel P4 3.2 Ghz, 1Go de Ram et accompagné d’une distribution Gnu/Linux Ubuntu Edgy Eft.

Version de Python : 2.4.4
Version de PHP : 5.1.6

Voici donc la version du script en PHP nommé test.php :

function test( $n )
{
if( $n <= 1 )return $n;
return test( $n - 1 ) + test( $n - 2 );
}
test( 35 );

et voici la version Python nommé test.py :

def test( n ):
if n <= 1:
return n
return test( n - 1 ) + test( n - 2 )
if __name__ == “__main__”:
test( 35 )

Maintenant que nous avons réalisé les deux scripts, il ne reste plus qu’à les exécuter. Pour cela nous allons utiliser un petit utilitaire fort sympathique (time) afin de connaître le temps d’exécution de chacun d’entre eux.

Voici donc le lancement du script PHP:

$ time php test.php

Les résultats que j’ai pu obtenir sur ma machine :

real 0m26.236s
user 0m25.846s
sys 0m0.012s

Voici donc le lancement du script Python:

$ time python test.py

Les résultats que j’ai pu obtenir sur ma machine :

real 0m15.110s
user 0m15.077s
sys 0m0.004s

Il semblerait donc que Python soit réellement plus performant sur ce type d’opération, mais bien sur on ne peut pas choisir un langage uniquement sur ce type comparatif. Néanmoins, il peut être intéressant de connaître les performances d’un langage avant de faire son choix.

[Plugin] Django AMF

12 février 2007, Aucun commentaire »

Pour toutes les personnes utilisant la technologie Flash, AMF PHP est souvent une réponse adéquate pour répondre à un nombre important de problèmes rencontrés lors du développement d’applications de type Flash Remoting.

Cette technologie séduisante pour le commun des flasheurs peut rebuter un passage de PHP à Django coté serveur.
Ce manque n’existe plus ! En effet, j’ai pu tomber par hasard sur le site DjangoAMF qui nous propose donc un middleware Django nous permettant d’utiliser le Flash Remoting. Ce plugin semble tout jeune (version 0.3.2) mais néanmoins actif (dernière mise à jour faite le 19 janvier 2007 )
Il semblerait qu’il soit développé par une équipe japonaise, mais fort heureusement une documentation anglaise est présente sur le site.
Je n’ai malheureusement pas encore eu le temps de tester tout cela, en espérant le faire dès que possible…