Design Patterns Python

Singleton

class Singleton(object):
    """ renvoie tjrs la même instance """
    _ref = None
    def __new__(cls, *args, **kw):
        if cls._ref is None:
            cls._ref = super(Singleton, cls).__new__(cls, *args, **kw)
        return cls._ref

class S(Singleton):
    pass

Observer

class Event(object):
    """ Classe événement """
    def __init__(self, name):
        self.name = name
        self._observateurs = []

    def __iadd__(self, observateur):
        """ ajoute un observateur """
        if not callable(observateur):
            raise TypeError("Doit être un objet appelable")
        observateurs = self._observateurs
        if observateur not in observateurs:
            observateurs.append(observateur)
        return self

    def __isub__(self, observateur):
        """ retire un observateur """
        observateurs = self._observateurs
        if observateur in observateurs:
            observers.remove(observateur)
        return self

    def __call__(self, *args, **kw):
        """ déclenche l'événement auprès de tous les inscrits """
        [observateur(*args, **kw) for observateur in self._observateurs]

utilisation

class Fenetre(object):
    def __init__(self, name):
        self.name = name
        self.titre = 'titre de la fenêtre'
        self.contenu = 'contenu de la fenêtre'
        self.titreEvent = Event('titre')
        self.contenuEvent = Event('contenu')
        globalTitreEvent = Event('titre global')

    def changeTitre(self, titre):
        self.titre = titre
        self.titreEvent(titre)
        Fenetre.globalTitreEvent(self.name, titre)

    def changeContenu(self, contenu):
        self.titre = contenu
        self.contenuEvent(contenu)

class ObservateurTitre(object):
    def __init__(self, fenetre):
        fenetre.titreEvent += self

    def __call__(self, titre):
        print ('le titre a été changé en "%s" !' % titre)

class ObservateurContenu(object):
    def __init__(self, fenetre):
        fenetre.contenuEvent += self.contenuChange

    def contenuChange(self, contenu):
        print('le contenu a été changé en "%s" !' % contenu)

class ObservateurGlobal(object):
    def __init__(self, fenetre):
        fenetre.globalTitreEvent += self

    def __call__(self, name, titre):
        print('le titre de "%s" a été changé en "%s" !' % (name, titre))

fenetre = Fenetre('fenetre 1')
fenetre2 = Fenetre('fenetre 2')
ob1 = ObservateurTitre(fenetre)
ob2 = ObservateurContenu(fenetre)
ob3 = ObservateurGlobal(fenetre)
fenetre.changeTitre('nouveau titre')
fenetre.changeContenu('nouveau contenu')
fenetre2.changeTitre('nouveau titre2')

Gestion des additions et soustractions d’attribut

méthode simple mais tout les attributs sont testés

class C(object):

    def __init__(self):
        self.x = 0
        self.y = 0

    def __setattr__(self, name, value):
        """Ne modifie pas x si la valeur est négative"""
        if name == 'x' and value < 0:
            return
        # Pour tout autre attribut on affecte la valeur
        object.__setattr__(self, name, value)

méthode plus fine

class UserList(object):
    def __init__(self, val=""):
        self._val = val

    def __add__(self, x):
        if len(self._val) > 0:
            return UserList(self._val + ',' + x)
        return UserList(x)

    def __iadd__(self, x):
        if len(self._val) > 0:
            self._val = self._val + ',' + x
        else:
            self._val = x
        return self

    def __sub__(self, x):
        return UserList(','.join([item for item in self._val.split(',') if item != x]))

    def __isub__(self, x):
        self._val = ','.join([item for item in self._val.split(',') if item != x])
        return self

    def __str__(self):
        return str(self._val)

    def __repr__(self):
        return str(self._val)

class Mail(object):
    def __init__(self, server="", subject="", to="", cc=None, dest=None):
        self._cc = UserList()
        self._for = UserList()
        self.server = server
        self.subject = subject
        self.msg = ""
        self.to = to

        if cc != None: self.cc += cc
        if dest != None: self.dest += dest

    def getcc(self):
        return self._cc

    def setcc(self, val):
        if not isinstance(val, UserList):
            val = UserList(val)
        self._cc = val

    def getdest(self):
        return self._for

    def setdest(self, val):
        if not isinstance(val, UserList):
            val = UserList(val)
        self._for = val

    cc = property(getcc, setcc)
    dest = property(getdest, setdest)

mail = Mail(server='srvxxxx1',
             subject='test',
             to='informatiquepz@myprop-group.com',
             cc='f.bourel@myprop-group.com',
             dest='a.billard@myprop-group.com')

mail.cc += 'f.gaborit@myprop-group.com'
mail.cc = mail.cc + 'f.aoustin@myprop-group.com'
mail.dest += 'appro3@myprop-group.com'
print mail.cc
print mail.dest
mail.cc -= 'f.bourel@myprop-group.com'
mail.cc = mail.cc - 'f.aoustin@myprop-group.com'
print mail.cc

producteur/consommateur

Le principe est le suivant:

  • des objets produisent des données (ou d’autres objets)
  • des objets consomment les données (ou des objets) produits par les producteurs

Il n’est possible que de consommer que ce qui est produit.

ON peut limiter le nombre d’objet à consommer ou à produire à un moment t.

Tout cela est le principe de la queue qui peut être du type FIFO, LILO ou prioritaire

Il existe pour gérer cette queue le module Queue dans python.

Dans l’exemple suivant nous gérons un magasin de stroumphs

import random
from Queue import *
from threading import Thread
import time

enStock = Queue(10)#notre pile, qui peut contenir 10 elements max( 0 pour enlever la limite)

class Magasin(Thread):
    """ Le 'producteur' : va remplir ses rayons de paquets de schtroumpfs"""
    def __init__(self):
        self.ouvert = True
        Thread.__init__(self)

    def run(self):
        while self.ouvert :

            while not enStock.full() :
                try :

                    enStock.put("ajout d'un paquet de schtroumpf",True,1000)
                    ### le Magasin va ajouter un paquet dans le rayon, et s'il y a plus de place,
                    ### va attendre pendant 1 seconde qu'un paquet soit achete .
                except Full,e :
                    print( "Il n'y a pas de place pour un paquet !\n");

                else:
                    print( "On ajoute un paquet de schtroumpfs dans le rayon\n")

            time.sleep(10)
            #on attend 10 secondes avant que le magasin aille alimenter le rayon


class Client(Thread):
    """ le consommateur, va prendre un/des paquet(s) de schtroumpf"""
    def __init__(self,faim,numero):
        self.jAiFaim = faim
        self.numero = numero
        Thread.__init__(self)



    def run(self):
        while self.jAiFaim :
            time.sleep(1)
            #le client arrive au bout d'une seconde au rayon

            ok=False
            paquet = random.randint(1,4)
            #nombre de paquet qu'il va prendre
            i=1
            print( "Le client n "+str(self.numero)+ " veut "+str(paquet)+ "paquet(s) de schtroumpfs\n")
            while i<=paquet :
                try:
                    enStock.get(True,500)
                    ok = True
                    print( "n "+ str(self.numero) +  ": Prend un paquet\n")

                except Empty, e:
                    ok = False
                    break
                else:
                    i+=1
            if ok :
                print( "Il reste  "+ str( enStock.qsize() ) + " paquet(s) de schtroumpfs\n")
            else :
                print( "n "+ str(self.numero) +  ": Il n'y a pas assez de paquets\n")
            self.jAiFaim = False

if __name__=='__main__':
    magasin = Magasin()
    magasin.ouvert = True
    print("##### Le magasin ouvre ses portes #####")
    magasin.start()

    i=1
    while i < 10:
        Client(faim = True ,numero = i).start()
        i=i+1

    time.sleep(60)
    magasin.ouvert=False
    print("##### Le magasin ferme ses portes #####")

les principales types de queues

  • Queue.Queue(maxsize=0)
  • Queue.LifoQueue(maxsize=0)
  • Queue.PriorityQueue(maxsize=0)

les principales fonctions

  • Queue.qsize()
  • Queue.empty()
  • Queue.full()
  • Queue.put(item[, block[, timeout]])
  • Queue.put_nowait(item)
  • Queue.get([block[, timeout]])
  • Queue.get_nowait()
  • Queue.task_done()
  • Queue.join()