Python Design Patterns - Guida rapida
I design pattern vengono utilizzati per rappresentare il pattern utilizzato dagli sviluppatori per creare software o applicazioni web. Questi modelli vengono selezionati in base all'analisi dei requisiti. I modelli descrivono la soluzione al problema, quando e dove applicare la soluzione e le conseguenze dell'implementazione.
Struttura di un modello di progettazione
La documentazione del design pattern viene mantenuta in un modo che si concentra maggiormente sulla tecnologia utilizzata e in quali modi. Il diagramma seguente spiega la struttura di base della documentazione del modello di progettazione.
Nome modello
Descrive il modello in modo breve ed efficace.
Intento / Motivo
Descrive cosa fa il modello.
Applicabilità
Descrive l'elenco delle situazioni in cui il modello è applicabile.
Partecipanti e conseguenze
I partecipanti includono classi e oggetti che partecipano al modello di progettazione con un elenco di conseguenze che esistono con il modello.
Perché Python?
Python è un linguaggio di scripting open source. Dispone di librerie che supportano una varietà di modelli di progettazione. La sintassi di python è facile da capire e utilizza parole chiave inglesi.
Python fornisce supporto per l'elenco dei modelli di progettazione menzionati di seguito. Questi modelli di progettazione verranno utilizzati in questo tutorial:
- Modello controller vista modello
- Modello singleton
- Modello di fabbrica
- Modello di generatore
- Modello prototipo
- Modello di facciata
- Modello di comando
- Modello adattatore
- Modello prototipo
- Decoratore Pattern
- Pattern proxy
- Schema della catena di responsabilità
- Pattern osservatore
- Modello di stato
- Modello di strategia
- Modello modello
- Modello Flyweight
- Modello astratto di fabbrica
- Pattern orientato agli oggetti
Vantaggi dell'utilizzo del modello di progettazione
Di seguito sono riportati i diversi vantaggi del design pattern:
I pattern forniscono agli sviluppatori una selezione di soluzioni collaudate per i problemi specificati.
Tutti i modelli di design sono indipendenti dal linguaggio.
I modelli aiutano a raggiungere la comunicazione e mantenere una buona documentazione.
Include un record di realizzazione per ridurre qualsiasi rischio tecnico per il progetto.
I modelli di progettazione sono altamente flessibili da usare e facili da capire.
Python è un linguaggio di scripting open source, di alto livello, interpretato, interattivo e orientato agli oggetti. È progettato per essere altamente leggibile. La sintassi del linguaggio Python è facile da capire e utilizza frequentemente parole chiave inglesi.
Caratteristiche del linguaggio Python
In questa sezione, impareremo le diverse caratteristiche del linguaggio Python.
Interpretato
Python viene elaborato in fase di esecuzione utilizzando l'interprete. Non è necessario compilare il programma prima dell'esecuzione. È simile a PERL e PHP.
Orientato agli oggetti
Python segue uno stile orientato agli oggetti e modelli di progettazione. Include la definizione della classe con varie caratteristiche come l'incapsulamento, il polimorfismo e molte altre.
Portatile
Codice Python scritto nel sistema operativo Windows e può essere utilizzato nel sistema operativo Mac. Il codice può essere riutilizzato e trasportabile secondo i requisiti.
Facile da codificare
La sintassi di Python è facile da capire e codificare. Qualsiasi sviluppatore può comprendere la sintassi di Python in poche ore. Python può essere descritto come "facile da programmare"
Estensibile
Se necessario, un utente può anche scrivere parte del codice Python in linguaggio C. È anche possibile inserire codice Python nel codice sorgente in diversi linguaggi come C ++. Questo rende Python un linguaggio estensibile.
Punti importanti
Considera i seguenti punti importanti relativi al linguaggio di programmazione Python:
Comprende metodi di programmazione funzionali e strutturati, nonché metodi di programmazione orientati agli oggetti.
Può essere utilizzato come linguaggio di scripting o come linguaggio di programmazione.
Include la raccolta automatica dei rifiuti.
Include tipi di dati dinamici di alto livello e supporta vari controlli dinamici del tipo.
Python include una funzionalità di integrazione con C, C ++ e linguaggi come Java.
Come scaricare il linguaggio Python nel tuo sistema?
Per scaricare il linguaggio Python nel tuo sistema, segui questo link -
https://www.python.org/downloads/Include pacchetti per vari sistemi operativi come Windows, MacOS e distribuzioni Linux.
Gli strumenti importanti in Python
In questa sezione, impareremo brevemente alcuni strumenti importanti in Python.
Stringhe Python
La dichiarazione di base delle stringhe è la seguente:
str = 'Hello World!'
Elenchi di Python
Gli elenchi di python possono essere dichiarati come tipi di dati composti separati da virgole e racchiusi tra parentesi quadre ([]).
list = [ 'abcd', 786 , 2.23, 'john', 70.2 ]
tinylist = [123, 'john']
Tuple Python
Una tupla è un tipo di dati dinamico di Python, che consiste in un numero di valori separati da virgole. Le tuple sono racchiuse tra parentesi.
tinytuple = (123, 'john')
Dizionario Python
Il dizionario Python è un tipo di tabella hash. Una chiave del dizionario può essere quasi qualsiasi tipo di dati di Python. I tipi di dati sono generalmente numeri o stringhe.
tinydict = {'name': 'omkar','code':6734, 'dept': 'sales'}
Cosa costituisce un modello di progettazione in Python?
Python aiuta a costituire un modello di progettazione utilizzando i seguenti parametri:
- Nome modello
- Intent
- Aliases
- Motivation
- Problem
- Solution
- Structure
- Participants
- Constraints
- Codice d'esempio
Model View Controller è il design pattern più comunemente utilizzato. Gli sviluppatori trovano facile implementare questo modello di progettazione.
Di seguito è riportata un'architettura di base del Model View Controller:
Vediamo ora come funziona la struttura.
Modello
Consiste in pura logica applicativa, che interagisce con il database. Include tutte le informazioni per rappresentare i dati per l'utente finale.
Visualizza
La vista rappresenta i file HTML, che interagiscono con l'utente finale. Rappresenta i dati del modello all'utente.
Controller
Funge da intermediario tra vista e modello. Ascolta gli eventi attivati dalla vista e interroga il modello per lo stesso.
Codice Python
Consideriamo un oggetto di base chiamato "Persona" e creiamo un modello di progettazione MVC.
Model.py
import json
class Person(object):
def __init__(self, first_name = None, last_name = None):
self.first_name = first_name
self.last_name = last_name
#returns Person name, ex: John Doe
def name(self):
return ("%s %s" % (self.first_name,self.last_name))
@classmethod
#returns all people inside db.txt as list of Person objects
def getAll(self):
database = open('db.txt', 'r')
result = []
json_list = json.loads(database.read())
for item in json_list:
item = json.loads(item)
person = Person(item['first_name'], item['last_name'])
result.append(person)
return result
Richiede un metodo, che recupera tutti i record della tabella Person nel database. I record sono presentati in formato JSON.
Visualizza
Visualizza tutti i record recuperati all'interno del modello. La vista non interagisce mai con il modello; il controller fa questo lavoro (comunicando con il modello e la vista).
from model import Person
def showAllView(list):
print 'In our db we have %i users. Here they are:' % len(list)
for item in list:
print item.name()
def startView():
print 'MVC - the simplest example'
print 'Do you want to see everyone in my db?[y/n]'
def endView():
print 'Goodbye!'
Controller
Il controller interagisce con il modello tramite getAll() metodo che recupera tutti i record visualizzati all'utente finale.
from model import Person
import view
def showAll():
#gets list of all Person objects
people_in_db = Person.getAll()
#calls view
return view.showAllView(people_in_db)
def start():
view.startView()
input = raw_input()
if input == 'y':
return showAll()
else:
return view.endView()
if __name__ == "__main__":
#running controller function
start()
Questo modello limita la creazione di istanze di una classe a un oggetto. È un tipo di pattern creazionale e coinvolge solo una classe per creare metodi e oggetti specificati.
Fornisce un punto di accesso globale all'istanza creata.
Come implementare una classe singleton?
Il seguente programma dimostra l'implementazione della classe singleton in cui stampa le istanze create più volte.
class Singleton:
__instance = None
@staticmethod
def getInstance():
""" Static access method. """
if Singleton.__instance == None:
Singleton()
return Singleton.__instance
def __init__(self):
""" Virtually private constructor. """
if Singleton.__instance != None:
raise Exception("This class is a singleton!")
else:
Singleton.__instance = self
s = Singleton()
print s
s = Singleton.getInstance()
print s
s = Singleton.getInstance()
print s
Produzione
Il programma di cui sopra genera il seguente output:
Il numero di istanze create è lo stesso e non c'è differenza negli oggetti elencati nell'output.
Il modello di fabbrica rientra nella categoria dell'elenco dei modelli di creazione. Fornisce uno dei modi migliori per creare un oggetto. Nel modello di fabbrica, gli oggetti vengono creati senza esporre la logica al client e fare riferimento all'oggetto appena creato utilizzando un'interfaccia comune.
I modelli di fabbrica vengono implementati in Python utilizzando il metodo di fabbrica. Quando un utente chiama un metodo in modo tale da passare una stringa e il valore restituito come nuovo oggetto viene implementato tramite il metodo factory. Il tipo di oggetto utilizzato nel metodo factory è determinato dalla stringa che viene passata attraverso il metodo.
Nell'esempio seguente, ogni metodo include object come parametro, che viene implementato tramite il metodo factory.
Come implementare un modello di fabbrica?
Vediamo ora come implementare un pattern factory.
class Button(object):
html = ""
def get_html(self):
return self.html
class Image(Button):
html = "<img></img>"
class Input(Button):
html = "<input></input>"
class Flash(Button):
html = "<obj></obj>"
class ButtonFactory():
def create_button(self, typ):
targetclass = typ.capitalize()
return globals()[targetclass]()
button_obj = ButtonFactory()
button = ['image', 'input', 'flash']
for b in button:
print button_obj.create_button(b).get_html()
La classe button aiuta a creare i tag html e la pagina html associata. Il client non avrà accesso alla logica del codice e l'output rappresenta la creazione della pagina html.
Produzione
Spiegazione
Il codice python include la logica dei tag html, il cui valore specificato. L'utente finale può dare un'occhiata al file HTML creato dal codice Python.
Builder Pattern è un modello di progettazione unico che aiuta a costruire oggetti complessi utilizzando oggetti semplici e utilizza un approccio algoritmico. Questo modello di design rientra nella categoria del modello creazionale. In questo modello di progettazione, una classe builder costruisce l'oggetto finale in una procedura dettagliata. Questo builder è indipendente da altri oggetti.
Vantaggi di Builder Pattern
Fornisce una chiara separazione e uno strato univoco tra la costruzione e la rappresentazione di un oggetto specificato creato dalla classe.
Fornisce un migliore controllo sul processo di costruzione del modello creato.
Fornisce lo scenario perfetto per cambiare la rappresentazione interna degli oggetti.
Come implementare il pattern builder?
In questa sezione impareremo come implementare il pattern builder.
class Director:
__builder = None
def setBuilder(self, builder):
self.__builder = builder
def getCar(self):
car = Car()
# First goes the body
body = self.__builder.getBody()
car.setBody(body)
# Then engine
engine = self.__builder.getEngine()
car.setEngine(engine)
# And four wheels
i = 0
while i < 4:
wheel = self.__builder.getWheel()
car.attachWheel(wheel)
i += 1
return car
# The whole product
class Car:
def __init__(self):
self.__wheels = list()
self.__engine = None
self.__body = None
def setBody(self, body):
self.__body = body
def attachWheel(self, wheel):
self.__wheels.append(wheel)
def setEngine(self, engine):
self.__engine = engine
def specification(self):
print "body: %s" % self.__body.shape
print "engine horsepower: %d" % self.__engine.horsepower
print "tire size: %d\'" % self.__wheels[0].size
class Builder:
def getWheel(self): pass
def getEngine(self): pass
def getBody(self): pass
class JeepBuilder(Builder):
def getWheel(self):
wheel = Wheel()
wheel.size = 22
return wheel
def getEngine(self):
engine = Engine()
engine.horsepower = 400
return engine
def getBody(self):
body = Body()
body.shape = "SUV"
return body
# Car parts
class Wheel:
size = None
class Engine:
horsepower = None
class Body:
shape = None
def main():
jeepBuilder = JeepBuilder() # initializing the class
director = Director()
# Build Jeep
print "Jeep"
director.setBuilder(jeepBuilder)
jeep = director.getCar()
jeep.specification()
print ""
if __name__ == "__main__":
main()
Produzione
Il programma di cui sopra genera il seguente output:
Il modello di progettazione del prototipo aiuta a nascondere la complessità delle istanze create dalla classe. Il concetto dell'oggetto esistente sarà diverso da quello del nuovo oggetto, che viene creato da zero.
L'oggetto appena copiato potrebbe avere alcune modifiche nelle proprietà, se necessario. Questo approccio consente di risparmiare tempo e risorse necessarie per lo sviluppo di un prodotto.
Come implementare un modello prototipo?
Vediamo ora come implementare un modello prototipo.
import copy
class Prototype:
_type = None
_value = None
def clone(self):
pass
def getType(self):
return self._type
def getValue(self):
return self._value
class Type1(Prototype):
def __init__(self, number):
self._type = "Type1"
self._value = number
def clone(self):
return copy.copy(self)
class Type2(Prototype):
""" Concrete prototype. """
def __init__(self, number):
self._type = "Type2"
self._value = number
def clone(self):
return copy.copy(self)
class ObjectFactory:
""" Manages prototypes.
Static factory, that encapsulates prototype
initialization and then allows instatiation
of the classes from these prototypes.
"""
__type1Value1 = None
__type1Value2 = None
__type2Value1 = None
__type2Value2 = None
@staticmethod
def initialize():
ObjectFactory.__type1Value1 = Type1(1)
ObjectFactory.__type1Value2 = Type1(2)
ObjectFactory.__type2Value1 = Type2(1)
ObjectFactory.__type2Value2 = Type2(2)
@staticmethod
def getType1Value1():
return ObjectFactory.__type1Value1.clone()
@staticmethod
def getType1Value2():
return ObjectFactory.__type1Value2.clone()
@staticmethod
def getType2Value1():
return ObjectFactory.__type2Value1.clone()
@staticmethod
def getType2Value2():
return ObjectFactory.__type2Value2.clone()
def main():
ObjectFactory.initialize()
instance = ObjectFactory.getType1Value1()
print "%s: %s" % (instance.getType(), instance.getValue())
instance = ObjectFactory.getType1Value2()
print "%s: %s" % (instance.getType(), instance.getValue())
instance = ObjectFactory.getType2Value1()
print "%s: %s" % (instance.getType(), instance.getValue())
instance = ObjectFactory.getType2Value2()
print "%s: %s" % (instance.getType(), instance.getValue())
if __name__ == "__main__":
main()
Produzione
Il programma precedente genererà il seguente output:
L'output aiuta a creare nuovi oggetti con quelli esistenti ed è chiaramente visibile nell'output di cui sopra.
Il modello di progettazione della facciata fornisce un'interfaccia unificata a una serie di interfacce in un sottosistema. Definisce un'interfaccia di livello superiore utilizzabile da qualsiasi sottosistema.
Una classe di facciata sa quale sottosistema è responsabile di una richiesta.
Come progettare un modello di facciata?
Vediamo ora come progettare un modello di facciata.
class _IgnitionSystem(object):
@staticmethod
def produce_spark():
return True
class _Engine(object):
def __init__(self):
self.revs_per_minute = 0
def turnon(self):
self.revs_per_minute = 2000
def turnoff(self):
self.revs_per_minute = 0
class _FuelTank(object):
def __init__(self, level=30):
self._level = level
@property
def level(self):
return self._level
@level.setter
def level(self, level):
self._level = level
class _DashBoardLight(object):
def __init__(self, is_on=False):
self._is_on = is_on
def __str__(self):
return self.__class__.__name__
@property
def is_on(self):
return self._is_on
@is_on.setter
def is_on(self, status):
self._is_on = status
def status_check(self):
if self._is_on:
print("{}: ON".format(str(self)))
else:
print("{}: OFF".format(str(self)))
class _HandBrakeLight(_DashBoardLight):
pass
class _FogLampLight(_DashBoardLight):
pass
class _Dashboard(object):
def __init__(self):
self.lights = {"handbreak": _HandBrakeLight(), "fog": _FogLampLight()}
def show(self):
for light in self.lights.values():
light.status_check()
# Facade
class Car(object):
def __init__(self):
self.ignition_system = _IgnitionSystem()
self.engine = _Engine()
self.fuel_tank = _FuelTank()
self.dashboard = _Dashboard()
@property
def km_per_litre(self):
return 17.0
def consume_fuel(self, km):
litres = min(self.fuel_tank.level, km / self.km_per_litre)
self.fuel_tank.level -= litres
def start(self):
print("\nStarting...")
self.dashboard.show()
if self.ignition_system.produce_spark():
self.engine.turnon()
else:
print("Can't start. Faulty ignition system")
def has_enough_fuel(self, km, km_per_litre):
litres_needed = km / km_per_litre
if self.fuel_tank.level > litres_needed:
return True
else:
return False
def drive(self, km = 100):
print("\n")
if self.engine.revs_per_minute > 0:
while self.has_enough_fuel(km, self.km_per_litre):
self.consume_fuel(km)
print("Drove {}km".format(km))
print("{:.2f}l of fuel still left".format(self.fuel_tank.level))
else:
print("Can't drive. The Engine is turned off!")
def park(self):
print("\nParking...")
self.dashboard.lights["handbreak"].is_on = True
self.dashboard.show()
self.engine.turnoff()
def switch_fog_lights(self, status):
print("\nSwitching {} fog lights...".format(status))
boolean = True if status == "ON" else False
self.dashboard.lights["fog"].is_on = boolean
self.dashboard.show()
def fill_up_tank(self):
print("\nFuel tank filled up!")
self.fuel_tank.level = 100
# the main function is the Client
def main():
car = Car()
car.start()
car.drive()
car.switch_fog_lights("ON")
car.switch_fog_lights("OFF")
car.park()
car.fill_up_tank()
car.drive()
car.start()
car.drive()
if __name__ == "__main__":
main()
Produzione
Il programma di cui sopra genera il seguente output:
Spiegazione
Questo programma è progettato con uno scenario. È quello di avviare il motore di un'auto o di qualsiasi veicolo in movimento. Se osservi il codice, include le funzioni associate per guidare, parcheggiare e anche consumare carburante.
Command Pattern aggiunge un livello di astrazione tra le azioni e include un oggetto, che richiama queste azioni.
In questo modello di progettazione, il client crea un oggetto comando che include un elenco di comandi da eseguire. L'oggetto comando creato implementa un'interfaccia specifica.
Di seguito è riportata l'architettura di base del modello di comando:
Come implementare il modello di comando?
Vedremo ora come implementare il design pattern.
def demo(a,b,c):
print 'a:',a
print 'b:',b
print 'c:',c
class Command:
def __init__(self, cmd, *args):
self._cmd=cmd
self._args=args
def __call__(self, *args):
return apply(self._cmd, self._args+args)
cmd = Command(dir,__builtins__)
print cmd()
cmd = Command(demo,1,2)
cmd(3)
Produzione
Il programma di cui sopra genera il seguente output:
Spiegazione
L'output implementa tutti i comandi e le parole chiave elencati nel linguaggio Python. Stampa i valori necessari delle variabili.
Il modello dell'adattatore funziona come un ponte tra due interfacce incompatibili. Questo tipo di modello di progettazione rientra nel modello strutturale poiché questo modello combina la capacità di due interfacce indipendenti.
Questo modello coinvolge una singola classe, che è responsabile di unire funzionalità di interfacce indipendenti o incompatibili. Un esempio di vita reale potrebbe essere il caso di un lettore di schede, che funge da adattatore tra la scheda di memoria e un laptop. Si collega la scheda di memoria al lettore di schede e il lettore di schede al laptop in modo che la scheda di memoria possa essere letta tramite il laptop.
Il modello di progettazione dell'adattatore aiuta a lavorare insieme le classi. Converte l'interfaccia di una classe in un'altra interfaccia in base ai requisiti. Il modello include una speciazione un polimorfismo che nomina un nome e più forme. Dire per una classe di forma che può essere utilizzata secondo i requisiti raccolti.
Esistono due tipi di modello di adattatore:
Modello adattatore oggetto
Questo modello di progettazione si basa sull'implementazione degli oggetti. Quindi, è chiamato Object Adapter Pattern.
Modello adattatore di classe
Questo è un modo alternativo per implementare il modello di progettazione dell'adattatore. Il modello può essere implementato utilizzando più eredità.
Come implementare il pattern dell'adattatore?
Vediamo ora come implementare il pattern dell'adattatore.
class EuropeanSocketInterface:
def voltage(self): pass
def live(self): pass
def neutral(self): pass
def earth(self): pass
# Adaptee
class Socket(EuropeanSocketInterface):
def voltage(self):
return 230
def live(self):
return 1
def neutral(self):
return -1
def earth(self):
return 0
# Target interface
class USASocketInterface:
def voltage(self): pass
def live(self): pass
def neutral(self): pass
# The Adapter
class Adapter(USASocketInterface):
__socket = None
def __init__(self, socket):
self.__socket = socket
def voltage(self):
return 110
def live(self):
return self.__socket.live()
def neutral(self):
return self.__socket.neutral()
# Client
class ElectricKettle:
__power = None
def __init__(self, power):
self.__power = power
def boil(self):
if self.__power.voltage() > 110:
print "Kettle on fire!"
else:
if self.__power.live() == 1 and \
self.__power.neutral() == -1:
print "Coffee time!"
else:
print "No power."
def main():
# Plug in
socket = Socket()
adapter = Adapter(socket)
kettle = ElectricKettle(adapter)
# Make coffee
kettle.boil()
return 0
if __name__ == "__main__":
main()
Produzione
Il programma di cui sopra genera il seguente output:
Spiegazione
Il codice include l'interfaccia dell'adattatore con vari parametri e attributi. Include Adaptee insieme all'interfaccia Target che implementa tutti gli attributi e visualizza l'output come visibile.
Il motivo Decorator consente a un utente di aggiungere nuove funzionalità a un oggetto esistente senza alterarne la struttura. Questo tipo di modello di progettazione rientra nel modello strutturale poiché questo modello funge da involucro per la classe esistente.
Questo modello crea una classe decoratore, che avvolge la classe originale e fornisce funzionalità aggiuntive mantenendo intatta la firma dei metodi di classe.
Il motivo di un motivo decorativo è attribuire dinamicamente responsabilità aggiuntive a un oggetto.
Come implementare il modello di progettazione del decoratore
Il codice indicato di seguito è una semplice dimostrazione di come implementare il modello di progettazione del decoratore in Python. L'illustrazione prevede la dimostrazione di una caffetteria nel formato di una lezione. La classe di caffè creata è un abstract, il che significa che non può essere istanziata.
import six
from abc import ABCMeta
@six.add_metaclass(ABCMeta)
class Abstract_Coffee(object):
def get_cost(self):
pass
def get_ingredients(self):
pass
def get_tax(self):
return 0.1*self.get_cost()
class Concrete_Coffee(Abstract_Coffee):
def get_cost(self):
return 1.00
def get_ingredients(self):
return 'coffee'
@six.add_metaclass(ABCMeta)
class Abstract_Coffee_Decorator(Abstract_Coffee):
def __init__(self,decorated_coffee):
self.decorated_coffee = decorated_coffee
def get_cost(self):
return self.decorated_coffee.get_cost()
def get_ingredients(self):
return self.decorated_coffee.get_ingredients()
class Sugar(Abstract_Coffee_Decorator):
def __init__(self,decorated_coffee):
Abstract_Coffee_Decorator.__init__(self,decorated_coffee)
def get_cost(self):
return self.decorated_coffee.get_cost()
def get_ingredients(self):
return self.decorated_coffee.get_ingredients() + ', sugar'
class Milk(Abstract_Coffee_Decorator):
def __init__(self,decorated_coffee):
Abstract_Coffee_Decorator.__init__(self,decorated_coffee)
def get_cost(self):
return self.decorated_coffee.get_cost() + 0.25
def get_ingredients(self):
return self.decorated_coffee.get_ingredients() + ', milk'
class Vanilla(Abstract_Coffee_Decorator):
def __init__(self,decorated_coffee):
Abstract_Coffee_Decorator.__init__(self,decorated_coffee)
def get_cost(self):
return self.decorated_coffee.get_cost() + 0.75
def get_ingredients(self):
return self.decorated_coffee.get_ingredients() + ', vanilla'
L'implementazione della classe astratta della caffetteria viene eseguita con un file separato come indicato di seguito -
import coffeeshop
myCoffee = coffeeshop.Concrete_Coffee()
print('Ingredients: '+myCoffee.get_ingredients()+
'; Cost: '+str(myCoffee.get_cost())+'; sales tax = '+str(myCoffee.get_tax()))
myCoffee = coffeeshop.Milk(myCoffee)
print('Ingredients: '+myCoffee.get_ingredients()+
'; Cost: '+str(myCoffee.get_cost())+'; sales tax = '+str(myCoffee.get_tax()))
myCoffee = coffeeshop.Vanilla(myCoffee)
print('Ingredients: '+myCoffee.get_ingredients()+
'; Cost: '+str(myCoffee.get_cost())+'; sales tax = '+str(myCoffee.get_tax()))
myCoffee = coffeeshop.Sugar(myCoffee)
print('Ingredients: '+myCoffee.get_ingredients()+
'; Cost: '+str(myCoffee.get_cost())+'; sales tax = '+str(myCoffee.get_tax()))
Produzione
Il programma di cui sopra genera il seguente output:
Il modello di progettazione proxy include un nuovo oggetto, chiamato "Proxy" al posto di un oggetto esistente, chiamato "Soggetto reale". L'oggetto proxy creato dal soggetto reale deve trovarsi sulla stessa interfaccia in modo tale che il client non debba avere alcuna idea che il proxy venga utilizzato al posto dell'oggetto reale. Le richieste generate dal client al proxy vengono passate attraverso il soggetto reale.
La rappresentazione UML del modello proxy è la seguente:
Come implementare il modello proxy?
Vediamo ora come implementare il modello proxy.
class Image:
def __init__( self, filename ):
self._filename = filename
def load_image_from_disk( self ):
print("loading " + self._filename )
def display_image( self ):
print("display " + self._filename)
class Proxy:
def __init__( self, subject ):
self._subject = subject
self._proxystate = None
class ProxyImage( Proxy ):
def display_image( self ):
if self._proxystate == None:
self._subject.load_image_from_disk()
self._proxystate = 1
print("display " + self._subject._filename )
proxy_image1 = ProxyImage ( Image("HiRes_10Mb_Photo1") )
proxy_image2 = ProxyImage ( Image("HiRes_10Mb_Photo2") )
proxy_image1.display_image() # loading necessary
proxy_image1.display_image() # loading unnecessary
proxy_image2.display_image() # loading necessary
proxy_image2.display_image() # loading unnecessary
proxy_image1.display_image() # loading unnecessary
Produzione
Il programma di cui sopra genera il seguente output:
Il design del modello proxy aiuta a replicare le immagini che abbiamo creato. La funzione display_image () aiuta a controllare se i valori vengono stampati nel prompt dei comandi.
Il modello della catena di responsabilità viene utilizzato per ottenere un accoppiamento libero nel software in cui una specifica richiesta del client viene passata attraverso una catena di oggetti inclusi in esso. Aiuta a costruire una catena di oggetti. La richiesta entra da un'estremità e si sposta da un oggetto all'altro.
Questo modello consente a un oggetto di inviare un comando senza sapere quale oggetto gestirà la richiesta.
Come implementare il modello della catena di responsabilità?
Vedremo ora come implementare il modello della catena di responsabilità.
class ReportFormat(object):
PDF = 0
TEXT = 1
class Report(object):
def __init__(self, format_):
self.title = 'Monthly report'
self.text = ['Things are going', 'really, really well.']
self.format_ = format_
class Handler(object):
def __init__(self):
self.nextHandler = None
def handle(self, request):
self.nextHandler.handle(request)
class PDFHandler(Handler):
def handle(self, request):
if request.format_ == ReportFormat.PDF:
self.output_report(request.title, request.text)
else:
super(PDFHandler, self).handle(request)
def output_report(self, title, text):
print '<html>'
print ' <head>'
print ' <title>%s</title>' % title
print ' </head>'
print ' <body>'
for line in text:
print ' <p>%s' % line
print ' </body>'
print '</html>'
class TextHandler(Handler):
def handle(self, request):
if request.format_ == ReportFormat.TEXT:
self.output_report(request.title, request.text)
else:
super(TextHandler, self).handle(request)
def output_report(self, title, text):
print 5*'*' + title + 5*'*'
for line in text:
print line
class ErrorHandler(Handler):
def handle(self, request):
print "Invalid request"
if __name__ == '__main__':
report = Report(ReportFormat.TEXT)
pdf_handler = PDFHandler()
text_handler = TextHandler()
pdf_handler.nextHandler = text_handler
text_handler.nextHandler = ErrorHandler()
pdf_handler.handle(report)
Produzione
Il programma di cui sopra genera il seguente output:
Spiegazione
Il codice precedente crea un report per le attività mensili in cui invia i comandi attraverso ciascuna funzione. Sono necessari due gestori: per PDF e per testo. Stampa l'output una volta che l'oggetto richiesto esegue ciascuna funzione.
In questo modello, gli oggetti sono rappresentati come osservatori che attendono l'attivazione di un evento. Un osservatore si attacca al soggetto una volta che si verifica l'evento specificato. Quando l'evento si verifica, il soggetto dice agli osservatori che si è verificato.
Il seguente diagramma UML rappresenta il modello dell'osservatore:
Come implementare il pattern dell'osservatore?
Vediamo ora come implementare il pattern dell'osservatore.
import threading
import time
import pdb
class Downloader(threading.Thread):
def run(self):
print 'downloading'
for i in range(1,5):
self.i = i
time.sleep(2)
print 'unfunf'
return 'hello world'
class Worker(threading.Thread):
def run(self):
for i in range(1,5):
print 'worker running: %i (%i)' % (i, t.i)
time.sleep(1)
t.join()
print 'done'
t = Downloader()
t.start()
time.sleep(1)
t1 = Worker()
t1.start()
t2 = Worker()
t2.start()
t3 = Worker()
t3.start()
Produzione
Il programma di cui sopra genera il seguente output:
Spiegazione
Il codice sopra spiega la procedura per scaricare un particolare risultato. Secondo la logica del pattern dell'osservatore, ogni oggetto viene trattato come osservatore. Stampa l'output quando viene attivato l'evento.
Fornisce un modulo per macchine a stati, implementate utilizzando sottoclassi, derivate da una classe di macchina a stati specificata. I metodi sono indipendenti dallo stato e causano transizioni dichiarate utilizzando decoratori.
Come implementare il modello statale?
L'implementazione di base del modello di stato è mostrata di seguito:
class ComputerState(object):
name = "state"
allowed = []
def switch(self, state):
""" Switch to new state """
if state.name in self.allowed:
print 'Current:',self,' => switched to new state',state.name
self.__class__ = state
else:
print 'Current:',self,' => switching to',state.name,'not possible.'
def __str__(self):
return self.name
class Off(ComputerState):
name = "off"
allowed = ['on']
class On(ComputerState):
""" State of being powered on and working """
name = "on"
allowed = ['off','suspend','hibernate']
class Suspend(ComputerState):
""" State of being in suspended mode after switched on """
name = "suspend"
allowed = ['on']
class Hibernate(ComputerState):
""" State of being in hibernation after powered on """
name = "hibernate"
allowed = ['on']
class Computer(object):
""" A class representing a computer """
def __init__(self, model='HP'):
self.model = model
# State of the computer - default is off.
self.state = Off()
def change(self, state):
""" Change state """
self.state.switch(state)
if __name__ == "__main__":
comp = Computer()
comp.change(On)
comp.change(Off)
comp.change(On)
comp.change(Suspend)
comp.change(Hibernate)
comp.change(On)
comp.change(Off)
Produzione
Il programma di cui sopra genera il seguente output:
Il modello strategico è un tipo di modello comportamentale. L'obiettivo principale del pattern strategico è consentire al cliente di scegliere tra diversi algoritmi o procedure per completare l'attività specificata. Diversi algoritmi possono essere scambiati dentro e fuori senza complicazioni per l'attività menzionata.
Questo modello può essere utilizzato per migliorare la flessibilità quando si accede a risorse esterne.
Come implementare il modello strategico?
Il programma mostrato di seguito aiuta nell'implementazione del modello di strategia.
import types
class StrategyExample:
def __init__(self, func = None):
self.name = 'Strategy Example 0'
if func is not None:
self.execute = types.MethodType(func, self)
def execute(self):
print(self.name)
def execute_replacement1(self):
print(self.name + 'from execute 1')
def execute_replacement2(self):
print(self.name + 'from execute 2')
if __name__ == '__main__':
strat0 = StrategyExample()
strat1 = StrategyExample(execute_replacement1)
strat1.name = 'Strategy Example 1'
strat2 = StrategyExample(execute_replacement2)
strat2.name = 'Strategy Example 2'
strat0.execute()
strat1.execute()
strat2.execute()
Produzione
Il programma di cui sopra genera il seguente output:
Spiegazione
Fornisce un elenco di strategie dalle funzioni, che eseguono l'output. L'obiettivo principale di questo modello di comportamento è il comportamento.
Un modello di modello definisce un algoritmo di base in una classe base utilizzando un'operazione astratta in cui le sottoclassi sovrascrivono il comportamento concreto. Il modello modello mantiene la struttura dell'algoritmo in un metodo separato. Questo metodo è denominato metodo modello.
Di seguito sono riportate le diverse caratteristiche del modello modello:
Definisce lo scheletro dell'algoritmo in un'operazione
Include sottoclassi, che ridefiniscono alcuni passaggi di un algoritmo.
class MakeMeal:
def prepare(self): pass
def cook(self): pass
def eat(self): pass
def go(self):
self.prepare()
self.cook()
self.eat()
class MakePizza(MakeMeal):
def prepare(self):
print "Prepare Pizza"
def cook(self):
print "Cook Pizza"
def eat(self):
print "Eat Pizza"
class MakeTea(MakeMeal):
def prepare(self):
print "Prepare Tea"
def cook(self):
print "Cook Tea"
def eat(self):
print "Eat Tea"
makePizza = MakePizza()
makePizza.go()
print 25*"+"
makeTea = MakeTea()
makeTea.go()
Produzione
Il programma di cui sopra genera il seguente output:
Spiegazione
Questo codice crea un modello per preparare il pasto. Qui, ogni parametro rappresenta l'attributo per creare una parte del pasto come tè, pizza, ecc.
L'output rappresenta la visualizzazione degli attributi.
Il modello flyweight rientra nella categoria dei modelli di progettazione strutturale. Fornisce un modo per diminuire il numero di oggetti. Include varie funzionalità che aiutano a migliorare la struttura dell'applicazione. La caratteristica più importante degli oggetti flyweight è immutabile. Ciò significa che non possono essere modificati una volta costruiti. Il modello utilizza una HashMap per memorizzare gli oggetti di riferimento.
Come implementare il modello flyweight?
Il seguente programma aiuta a implementare il modello dei pesi mosca:
class ComplexGenetics(object):
def __init__(self):
pass
def genes(self, gene_code):
return "ComplexPatter[%s]TooHugeinSize" % (gene_code)
class Families(object):
family = {}
def __new__(cls, name, family_id):
try:
id = cls.family[family_id]
except KeyError:
id = object.__new__(cls)
cls.family[family_id] = id
return id
def set_genetic_info(self, genetic_info):
cg = ComplexGenetics()
self.genetic_info = cg.genes(genetic_info)
def get_genetic_info(self):
return (self.genetic_info)
def test():
data = (('a', 1, 'ATAG'), ('a', 2, 'AAGT'), ('b', 1, 'ATAG'))
family_objects = []
for i in data:
obj = Families(i[0], i[1])
obj.set_genetic_info(i[2])
family_objects.append(obj)
for i in family_objects:
print "id = " + str(id(i))
print i.get_genetic_info()
print "similar id's says that they are same objects "
if __name__ == '__main__':
test()
Produzione
Il programma di cui sopra genera il seguente output:
Il modello astratto della fabbrica è anche chiamato fabbrica delle fabbriche. Questo modello di design rientra nella categoria del modello di progettazione creazionale. Fornisce uno dei modi migliori per creare un oggetto.
Include un'interfaccia, responsabile della creazione di oggetti relativi a Factory.
Come implementare il modello di fabbrica astratto?
Il seguente programma aiuta nell'implementazione del pattern factory astratto.
class Window:
__toolkit = ""
__purpose = ""
def __init__(self, toolkit, purpose):
self.__toolkit = toolkit
self.__purpose = purpose
def getToolkit(self):
return self.__toolkit
def getType(self):
return self.__purpose
class GtkToolboxWindow(Window):
def __init__(self):
Window.__init__(self, "Gtk", "ToolboxWindow")
class GtkLayersWindow(Window):
def __init__(self):
Window.__init__(self, "Gtk", "LayersWindow")
class GtkMainWindow(Window):
def __init__(self):
Window.__init__(self, "Gtk", "MainWindow")
class QtToolboxWindow(Window):
def __init__(self):
Window.__init__(self, "Qt", "ToolboxWindow")
class QtLayersWindow(Window):
def __init__(self):
Window.__init__(self, "Qt", "LayersWindow")
class QtMainWindow(Window):
def __init__(self):
Window.__init__(self, "Qt", "MainWindow")
# Abstract factory class
class UIFactory:
def getToolboxWindow(self): pass
def getLayersWindow(self): pass
def getMainWindow(self): pass
class GtkUIFactory(UIFactory):
def getToolboxWindow(self):
return GtkToolboxWindow()
def getLayersWindow(self):
return GtkLayersWindow()
def getMainWindow(self):
return GtkMainWindow()
class QtUIFactory(UIFactory):
def getToolboxWindow(self):
return QtToolboxWindow()
def getLayersWindow(self):
return QtLayersWindow()
def getMainWindow(self):
return QtMainWindow()
if __name__ == "__main__":
gnome = True
kde = not gnome
if gnome:
ui = GtkUIFactory()
elif kde:
ui = QtUIFactory()
toolbox = ui.getToolboxWindow()
layers = ui.getLayersWindow()
main = ui.getMainWindow()
print "%s:%s" % (toolbox.getToolkit(), toolbox.getType())
print "%s:%s" % (layers.getToolkit(), layers.getType())
print "%s:%s" % (main.getToolkit(), main.getType())
Produzione
Il programma di cui sopra genera il seguente output:
Spiegazione
Nel programma sopra, la fabbrica astratta crea oggetti per ogni finestra. Richiama ogni metodo, che esegue l'output come previsto.
Il pattern orientato agli oggetti è il pattern più comunemente usato. Questo modello può essere trovato in quasi tutti i linguaggi di programmazione.
Come implementare il pattern orientato agli oggetti?
Vediamo ora come implementare il pattern orientato agli oggetti.
class Parrot:
# class attribute
species = "bird"
# instance attribute
def __init__(self, name, age):
self.name = name
self.age = age
# instantiate the Parrot class
blu = Parrot("Blu", 10)
woo = Parrot("Woo", 15)
# access the class attributes
print("Blu is a {}".format(blu.__class__.species))
print("Woo is also a {}".format(woo.__class__.species))
# access the instance attributes
print("{} is {} years old".format( blu.name, blu.age))
print("{} is {} years old".format( woo.name, woo.age))
Produzione
Il programma precedente genera il seguente output
Spiegazione
Il codice include l'attributo di classe e gli attributi di istanza, che vengono stampati secondo il requisito dell'output. Ci sono varie caratteristiche che fanno parte del modello orientato agli oggetti. Le caratteristiche sono spiegate nel prossimo capitolo.
In questo capitolo, ci concentreremo sui modelli che utilizzano concetti orientati agli oggetti e la loro implementazione in Python. Quando progettiamo i nostri programmi attorno a blocchi di istruzioni, che manipolano i dati attorno alle funzioni, si parla di programmazione orientata alle procedure. Nella programmazione orientata agli oggetti, ci sono due istanze principali chiamate classi e oggetti.
Come implementare classi e variabili oggetto?
L'implementazione di classi e variabili oggetto è la seguente:
class Robot:
population = 0
def __init__(self, name):
self.name = name
print("(Initializing {})".format(self.name))
Robot.population += 1
def die(self):
print("{} is being destroyed!".format(self.name))
Robot.population -= 1
if Robot.population == 0:
print("{} was the last one.".format(self.name))
else:
print("There are still {:d} robots working.".format(
Robot.population))
def say_hi(self):
print("Greetings, my masters call me {}.".format(self.name))
@classmethod
def how_many(cls):
print("We have {:d} robots.".format(cls.population))
droid1 = Robot("R2-D2")
droid1.say_hi()
Robot.how_many()
droid2 = Robot("C-3PO")
droid2.say_hi()
Robot.how_many()
print("\nRobots can do some work here.\n")
print("Robots have finished their work. So let's destroy them.")
droid1.die()
droid2.die()
Robot.how_many()
Produzione
Il programma di cui sopra genera il seguente output:
Spiegazione
Questa illustrazione aiuta a dimostrare la natura delle variabili di classe e oggetto.
"Popolazione" appartiene alla classe "Robot". Quindi, viene indicato come una variabile di classe o un oggetto.
Qui, ci riferiamo alla variabile della classe di popolazione come Robot.population e non come self.population.
Il modello di progettazione dell'iteratore rientra nella categoria dei modelli di progettazione comportamentale. Gli sviluppatori si imbattono nel modello iteratore in quasi tutti i linguaggi di programmazione. Questo modello viene utilizzato in modo tale da aiutare ad accedere agli elementi di una raccolta (classe) in modo sequenziale senza comprendere il design del livello sottostante.
Come implementare il pattern iteratore?
Vedremo ora come implementare il pattern iteratore.
import time
def fib():
a, b = 0, 1
while True:
yield b
a, b = b, a + b
g = fib()
try:
for e in g:
print(e)
time.sleep(1)
except KeyboardInterrupt:
print("Calculation stopped")
Produzione
Il programma di cui sopra genera il seguente output:
Se ti concentri sul pattern, la serie di Fibonacci viene stampata con il pattern iteratore. Alla chiusura forzata dell'utente, viene stampato il seguente output:
Spiegazione
Questo codice Python segue il modello iteratore. Qui, gli operatori di incremento vengono utilizzati per avviare il conteggio. Il conteggio termina con la risoluzione forzata da parte dell'utente.
I dizionari sono le strutture di dati, che includono una combinazione di valori chiave. Questi sono ampiamente utilizzati al posto di JSON - JavaScript Object Notation. I dizionari vengono utilizzati per la programmazione API (Application Programming Interface). Un dizionario mappa un insieme di oggetti su un altro insieme di oggetti. I dizionari sono mutabili; questo significa che possono essere modificati come e quando necessario in base ai requisiti.
Come implementare i dizionari in Python?
Il seguente programma mostra l'implementazione di base dei dizionari in Python a partire dalla sua creazione fino alla sua implementazione.
# Create a new dictionary
d = dict() # or d = {}
# Add a key - value pairs to dictionary
d['xyz'] = 123
d['abc'] = 345
# print the whole dictionary
print(d)
# print only the keys
print(d.keys())
# print only values
print(d.values())
# iterate over dictionary
for i in d :
print("%s %d" %(i, d[i]))
# another method of iteration
for index, value in enumerate(d):
print (index, value , d[value])
# check if key exist 23. Python Data Structure –print('xyz' in d)
# delete the key-value pair
del d['xyz']
# check again
print("xyz" in d)
Produzione
Il programma di cui sopra genera il seguente output:
Note −Ci sono degli svantaggi legati all'implementazione dei dizionari in Python.
Inconveniente
I dizionari non supportano l'operazione di sequenza dei tipi di dati di sequenza come stringhe, tuple ed elenchi. Questi appartengono al tipo di mappatura integrato.
La struttura dati Lists è un tipo di dati versatile in Python, che può essere scritto come un elenco di valori separati da virgole tra parentesi quadre.
Sintassi
Ecco la sintassi di base per la struttura:
List_name = [ elements ];
Se osservi, la sintassi è dichiarata come array con l'unica differenza che gli elenchi possono includere elementi con diversi tipi di dati. Gli array includono elementi dello stesso tipo di dati. Un elenco può contenere una combinazione di stringhe, numeri interi e oggetti. Gli elenchi possono essere utilizzati per l'implementazione di stack e code.
Gli elenchi sono modificabili. Questi possono essere modificati come e quando necessario.
Come implementare gli elenchi?
Il seguente programma mostra le implementazioni degli elenchi:
my_list = ['p','r','o','b','e']
# Output: p
print(my_list[0])
# Output: o
print(my_list[2])
# Output: e
print(my_list[4])
# Error! Only integer can be used for indexing
# my_list[4.0]
# Nested List
n_list = ["Happy", [2,0,1,5]]
# Nested indexing
# Output: a
print(n_list[0][1])
# Output: 5
print(n_list[1][3])
Produzione
Il programma di cui sopra genera il seguente output:
Le funzioni integrate degli elenchi di Python sono le seguenti:
Append()- Aggiunge un elemento alla fine della lista.
Extend()- Aggiunge elementi dell'elenco a un altro elenco.
Insert()- Inserisce un elemento nell'indice definito.
Remove()- Elimina l'elemento dall'elenco specificato.
Reverse()- Inverte gli elementi in lista.
sort() - Aiuta a ordinare gli elementi in ordine cronologico.
Un insieme può essere definito come raccolta non ordinata che è iterabile, modificabile e non vi è inclusione di elementi duplicati in essa. In Python, set class è una notazione di set matematico. Il vantaggio principale dell'utilizzo di un set è che include un metodo altamente ottimizzato per il controllo di elementi specifici.
Python include una categoria separata chiamata set congelati. Questi set sono oggetti immutabili che supportano solo metodi e operatori che producono un risultato richiesto.
Come implementare i set?
Il seguente programma aiuta nell'implementazione dei set:
# Set in Python
# Creating two sets
set1 = set()
set2 = set()
# Adding elements to set1
for i in range(1, 6):
set1.add(i)
# Adding elements to set2
for i in range(3, 8):
set2.add(i)
print("Set1 = ", set1)
print("Set2 = ", set2)
print("\n")
# Union of set1 and set2
set3 = set1 | set2# set1.union(set2)
print("Union of Set1 & Set2: Set3 = ", set3)
# Intersection of set1 and set2
set4 = set1 & set2# set1.intersection(set2)
print("Intersection of Set1 & Set2: Set4 = ", set4)
print("\n")
# Checking relation between set3 and set4
if set3 > set4: # set3.issuperset(set4)
print("Set3 is superset of Set4")
elif set3 < set4: # set3.issubset(set4)
print("Set3 is subset of Set4")
else : # set3 == set4
print("Set3 is same as Set4")
# displaying relation between set4 and set3
if set4 < set3: # set4.issubset(set3)
print("Set4 is subset of Set3")
print("\n")
# difference between set3 and set4
set5 = set3 - set4
print("Elements in Set3 and not in Set4: Set5 = ", set5)
print("\n")
# checkv if set4 and set5 are disjoint sets
if set4.isdisjoint(set5):
print("Set4 and Set5 have nothing in common\n")
# Removing all the values of set5
set5.clear()
print("After applying clear on sets Set5: ")
print("Set5 = ", set5)
Produzione
Il programma di cui sopra genera il seguente output:
Il set congelato può essere dimostrato utilizzando il seguente programma:
normal_set = set(["a", "b","c"])
# Adding an element to normal set is fine
normal_set.add("d")
print("Normal Set")
print(normal_set)
# A frozen set
frozen_set = frozenset(["e", "f", "g"])
print("Frozen Set")
print(frozen_set)
Produzione
Il programma di cui sopra genera il seguente output:
Queue è una raccolta di oggetti, che definiscono una struttura dati semplice seguendo le procedure FIFO (Fast In Fast Out) e LIFO (Last In First Out). Le operazioni di inserimento ed eliminazione sono denominateenqueue e dequeue operazioni.
Le code non consentono l'accesso casuale agli oggetti che contengono.
Come implementare la procedura FIFO?
Il seguente programma aiuta nell'implementazione di FIFO:
import Queue
q = Queue.Queue()
#put items at the end of the queue
for x in range(4):
q.put("item-" + str(x))
#remove items from the head of the queue
while not q.empty():
print q.get()
Produzione
Il programma di cui sopra genera il seguente output:
Come implementare la procedura LIFO?
Il seguente programma aiuta nell'implementazione della procedura LIFO:
import Queue
q = Queue.LifoQueue()
#add items at the head of the queue
for x in range(4):
q.put("item-" + str(x))
#remove items from the head of the queue
while not q.empty():
print q.get()
Produzione
Il programma di cui sopra genera il seguente output:
Cos'è una coda prioritaria?
La coda prioritaria è una struttura di dati del contenitore che gestisce un set di record con le chiavi ordinate per fornire un accesso rapido al record con la chiave più piccola o più grande nella struttura dati specificata.
Come implementare una coda prioritaria?
L'implementazione della coda di priorità è la seguente:
import Queue
class Task(object):
def __init__(self, priority, name):
self.priority = priority
self.name = name
def __cmp__(self, other):
return cmp(self.priority, other.priority)
q = Queue.PriorityQueue()
q.put( Task(100, 'a not agent task') )
q.put( Task(5, 'a highly agent task') )
q.put( Task(10, 'an important task') )
while not q.empty():
cur_task = q.get()
print 'process task:', cur_task.name
Produzione
Il programma di cui sopra genera il seguente output:
La serializzazione delle stringhe è il processo di scrittura di uno stato di un oggetto in un flusso di byte. In python, la libreria "pickle" viene utilizzata per abilitare la serializzazione. Questo modulo include un potente algoritmo per serializzare e deserializzare una struttura di oggetti Python. "Pickling" è il processo di conversione della gerarchia di oggetti Python in flusso di byte e "unpickling" è la procedura inversa.
La dimostrazione del modulo pickle è la seguente:
import pickle
#Here's an example dict
grades = { 'Alice': 89, 'Bob': 72, 'Charles': 87 }
#Use dumps to convert the object to a serialized string
serial_grades = pickle.dumps( grades )
print(serial_grades)
#Use loads to de-serialize an object
received_grades = pickle.loads( serial_grades )
print(received_grades)
Produzione
Il programma di cui sopra genera il seguente output:
La concorrenza è spesso fraintesa come parallelismo. La concorrenza implica la pianificazione del codice indipendente da eseguire in modo sistematico. Questo capitolo si concentra sull'esecuzione della concorrenza per un sistema operativo che utilizza Python.
Il seguente programma aiuta nell'esecuzione della concorrenza per un sistema operativo:
import os
import time
import threading
import multiprocessing
NUM_WORKERS = 4
def only_sleep():
print("PID: %s, Process Name: %s, Thread Name: %s" % (
os.getpid(),
multiprocessing.current_process().name,
threading.current_thread().name)
)
time.sleep(1)
def crunch_numbers():
print("PID: %s, Process Name: %s, Thread Name: %s" % (
os.getpid(),
multiprocessing.current_process().name,
threading.current_thread().name)
)
x = 0
while x < 10000000:
x += 1
for _ in range(NUM_WORKERS):
only_sleep()
end_time = time.time()
print("Serial time=", end_time - start_time)
# Run tasks using threads
start_time = time.time()
threads = [threading.Thread(target=only_sleep) for _ in range(NUM_WORKERS)]
[thread.start() for thread in threads]
[thread.join() for thread in threads]
end_time = time.time()
print("Threads time=", end_time - start_time)
# Run tasks using processes
start_time = time.time()
processes = [multiprocessing.Process(target=only_sleep()) for _ in range(NUM_WORKERS)]
[process.start() for process in processes]
[process.join() for process in processes]
end_time = time.time()
print("Parallel time=", end_time - start_time)
Produzione
Il programma di cui sopra genera il seguente output:
Spiegazione
"Multiprocessing" è un pacchetto simile al modulo threading. Questo pacchetto supporta la concorrenza locale e remota. Grazie a questo modulo, i programmatori ottengono il vantaggio di utilizzare più processi su un determinato sistema.
Gli anti-pattern seguono una strategia in opposizione ai modelli di design predefiniti. La strategia include approcci comuni a problemi comuni, che possono essere formalizzati e possono essere generalmente considerati come una buona pratica di sviluppo. Di solito, gli anti-pattern sono opposti e indesiderabili. Gli anti-pattern sono determinati modelli utilizzati nello sviluppo del software, che sono considerati cattive pratiche di programmazione.
Caratteristiche importanti degli anti-pattern
Vediamo ora alcune importanti caratteristiche degli anti-modelli.
Correttezza
Questi schemi rompono letteralmente il codice e ti fanno fare cose sbagliate. Di seguito è riportato un semplice esempio di questo:
class Rectangle(object):
def __init__(self, width, height):
self._width = width
self._height = height
r = Rectangle(5, 6)
# direct access of protected member
print("Width: {:d}".format(r._width))
Manutenibilità
Si dice che un programma sia mantenibile se è facile da capire e modificare secondo il requisito. L'importazione del modulo può essere considerata un esempio di manutenibilità.
import math
x = math.ceil(y)
# or
import multiprocessing as mp
pool = mp.pool(8)
Esempio di anti-pattern
L'esempio seguente aiuta nella dimostrazione di anti-pattern -
#Bad
def filter_for_foo(l):
r = [e for e in l if e.find("foo") != -1]
if not check_some_critical_condition(r):
return None
return r
res = filter_for_foo(["bar","foo","faz"])
if res is not None:
#continue processing
pass
#Good
def filter_for_foo(l):
r = [e for e in l if e.find("foo") != -1]
if not check_some_critical_condition(r):
raise SomeException("critical condition unmet!")
return r
try:
res = filter_for_foo(["bar","foo","faz"])
#continue processing
except SomeException:
i = 0
while i < 10:
do_something()
#we forget to increment i
Spiegazione
L'esempio include la dimostrazione di standard buoni e cattivi per la creazione di una funzione in Python.
La gestione delle eccezioni è anche un criterio primario dei modelli di progettazione. Un'eccezione è un errore che si verifica durante l'esecuzione di un programma. Quando si verifica un errore particolare, è importante generare un'eccezione. Questo aiuta a frenare i crash del programma.
Perché utilizzare le eccezioni?
Le eccezioni sono modi convenienti per gestire errori e condizioni speciali in un programma. Quando un utente pensa che il codice specificato possa produrre un errore, è importante utilizzare la gestione delle eccezioni.
Esempio: divisione per zero
import sys
randomList = ['a', 0, 2]
for entry in randomList:
try:
print("The entry is", entry)
r = 1/int(entry)
break
except:
print("Oops!",sys.exc_info()[0],"occured.")
print("Next entry.")
print()
print("The reciprocal of",entry,"is",r)
Produzione
Il programma di cui sopra genera il seguente output:
Sollevare eccezioni
Nella programmazione Python in particolare, vengono sollevate eccezioni quando si verifica un errore di codice corrispondente in fase di esecuzione. Questo può essere sollevato con forza usando il“raise” parola chiave.
Sintassi
raise KeyboardInterrupt
Traceback (most recent call last):
...
KeyboardInterrupt