Python Design Patterns - Guia rápido
Os padrões de design são usados para representar o padrão usado pelos desenvolvedores para criar software ou aplicativo da web. Esses padrões são selecionados com base na análise de requisitos. Os padrões descrevem a solução para o problema, quando e onde aplicar a solução e as consequências da implementação.
Estrutura de um padrão de design
A documentação do design pattern é mantida de uma forma que enfoca mais a tecnologia que é usada e de que forma. O diagrama a seguir explica a estrutura básica da documentação do padrão de design.
Nome do Padrão
Ele descreve o padrão de maneira curta e eficaz.
Intenção / Motivo
Ele descreve o que o padrão faz.
Aplicabilidade
Ele descreve a lista de situações onde o padrão é aplicável.
Participantes e consequências
Os participantes incluem classes e objetos que participam do padrão de design com uma lista de consequências que existem com o padrão.
Por que Python?
Python é uma linguagem de script de código aberto. Possui bibliotecas que oferecem suporte a uma variedade de padrões de design. A sintaxe do python é fácil de entender e usa palavras-chave em inglês.
Python fornece suporte para a lista de padrões de design mencionados abaixo. Esses padrões de design serão usados ao longo deste tutorial -
- Padrão de controlador de visualização de modelo
- Padrão Singleton
- Padrão de fábrica
- Padrão de Construtor
- Padrão de Protótipo
- Padrão de fachada
- Padrão de Comando
- Padrão Adaptador
- Padrão de Protótipo
- Padrão Decorator
- Padrão Proxy
- Padrão de Cadeia de Responsabilidade
- Padrão Observador
- Padrão de Estado
- Padrão de Estratégia
- Padrão de modelo
- Padrão Flyweight
- Padrão de fábrica abstrata
- Padrão Orientado a Objetos
Benefícios de usar o padrão de design
A seguir estão os diferentes benefícios do padrão de design -
Os padrões fornecem ao desenvolvedor uma seleção de soluções experimentadas e testadas para os problemas especificados.
Todos os padrões de design são neutros em termos de linguagem.
Os padrões ajudam a alcançar a comunicação e a manter uma boa documentação.
Inclui um registro de realização para reduzir qualquer risco técnico para o projeto.
Os padrões de design são altamente flexíveis de usar e fáceis de entender.
Python é uma linguagem de script de código aberto, de alto nível, interpretada, interativa e orientada a objetos. Ele é projetado para ser altamente legível. A sintaxe da linguagem Python é fácil de entender e usa palavras-chave em inglês com frequência.
Recursos da linguagem Python
Nesta seção, aprenderemos sobre os diferentes recursos da linguagem Python.
Interpretado
Python é processado em tempo de execução usando o interpretador. Não há necessidade de compilar o programa antes da execução. É semelhante a PERL e PHP.
Orientado a Objeto
Python segue o estilo orientado a objetos e padrões de design. Inclui definição de classe com vários recursos como encapsulamento, polimorfismo e muitos mais.
Portátil
Código Python escrito no sistema operacional Windows e pode ser usado no sistema operacional Mac. O código pode ser reutilizado e portável de acordo com os requisitos.
Fácil de codificar
A sintaxe Python é fácil de entender e codificar. Qualquer desenvolvedor pode entender a sintaxe do Python em poucas horas. Python pode ser descrito como “amigável ao programador”
Extensível
Se necessário, um usuário pode escrever parte do código Python na linguagem C também. Também é possível colocar o código python no código-fonte em diferentes linguagens como C ++. Isso torna o Python uma linguagem extensível.
Pontos importantes
Considere os seguintes pontos importantes relacionados à linguagem de programação Python -
Inclui métodos de programação funcionais e estruturados, bem como métodos de programação orientados a objetos.
Pode ser usado como linguagem de script ou como linguagem de programação.
Inclui coleta automática de lixo.
Inclui tipos de dados dinâmicos de alto nível e oferece suporte a várias verificações de tipo dinâmico.
Python inclui um recurso de integração com C, C ++ e linguagens como Java.
Como baixar a linguagem python em seu sistema?
Para baixar a linguagem Python em seu sistema, siga este link -
https://www.python.org/downloads/Inclui pacotes para vários sistemas operacionais como distribuições Windows, MacOS e Linux.
As ferramentas importantes em Python
Nesta seção, aprenderemos resumidamente sobre algumas ferramentas importantes em Python.
Python Strings
A declaração básica de strings é a seguinte -
str = 'Hello World!'
Listas Python
As listas de python podem ser declaradas como tipos de dados compostos separados por vírgulas e colocados entre colchetes ([]).
list = [ 'abcd', 786 , 2.23, 'john', 70.2 ]
tinylist = [123, 'john']
Python Tuples
Uma tupla é um tipo de dados dinâmico do Python, que consiste em vários valores separados por vírgulas. As tuplas estão entre parênteses.
tinytuple = (123, 'john')
Dicionário Python
O dicionário Python é um tipo de tabela hash. Uma chave de dicionário pode ser quase qualquer tipo de dados de Python. Os tipos de dados geralmente são números ou strings.
tinydict = {'name': 'omkar','code':6734, 'dept': 'sales'}
O que constitui um padrão de design em Python?
Python ajuda a constituir um padrão de design usando os seguintes parâmetros -
- Nome do Padrão
- Intent
- Aliases
- Motivation
- Problem
- Solution
- Structure
- Participants
- Constraints
- Código de amostra
Model View Controller é o padrão de design mais comumente usado. Os desenvolvedores acham fácil implementar esse padrão de design.
A seguir está uma arquitetura básica do Model View Controller -
Vamos agora ver como funciona a estrutura.
Modelo
Consiste na pura lógica do aplicativo, que interage com o banco de dados. Inclui todas as informações para representar os dados para o usuário final.
Visão
View representa os arquivos HTML, que interagem com o usuário final. Ele representa os dados do modelo para o usuário.
Controlador
Ele atua como um intermediário entre a visualização e o modelo. Ele ouve os eventos disparados pelo modelo de visualização e consultas para os mesmos.
Código Python
Vamos considerar um objeto básico chamado “Pessoa” e criar um padrão de projeto 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
Ele chama um método que busca todos os registros da tabela Person no banco de dados. Os registros são apresentados no formato JSON.
Visão
Ele exibe todos os registros buscados no modelo. O modo de exibição nunca interage com o modelo; o controlador faz esse trabalho (comunicando-se com o modelo e a visualização).
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!'
Controlador
O controlador interage com o modelo por meio do getAll() método que busca todos os registros exibidos para o usuário final.
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()
Este padrão restringe a instanciação de uma classe a um objeto. É um tipo de padrão de criação e envolve apenas uma classe para criar métodos e objetos especificados.
Ele fornece um ponto global de acesso à instância criada.
Como implementar uma classe singleton?
O programa a seguir demonstra a implementação da classe singleton onde imprime as instâncias criadas várias vezes.
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
Resultado
O programa acima gera a seguinte saída -
O número de instâncias criadas é o mesmo e não há diferença nos objetos listados na saída.
O padrão de fábrica vem na categoria de lista de padrões de criação. Ele fornece uma das melhores maneiras de criar um objeto. No padrão de fábrica, os objetos são criados sem expor a lógica ao cliente e referindo-se ao objeto recém-criado usando uma interface comum.
Os padrões de fábrica são implementados em Python usando o método de fábrica. Quando um usuário chama um método, passamos uma string e o valor de retorno como um novo objeto é implementado por meio do método de fábrica. O tipo de objeto usado no método de fábrica é determinado por uma string que é passada pelo método.
No exemplo abaixo, todo método inclui objeto como parâmetro, que é implementado por meio do método de fábrica.
Como implementar um padrão de fábrica?
Vamos agora ver como implementar um padrão de fábrica.
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()
A classe do botão ajuda a criar as tags html e a página html associada. O cliente não terá acesso à lógica do código e a saída representa a criação da página html.
Resultado
Explicação
O código python inclui a lógica de tags html, cujo valor especificado. O usuário final pode dar uma olhada no arquivo HTML criado pelo código Python.
Builder Pattern é um padrão de design exclusivo que ajuda na construção de objetos complexos usando objetos simples e usa uma abordagem algorítmica. Este padrão de design vem na categoria de padrão de criação. Nesse padrão de design, uma classe de construtor constrói o objeto final no procedimento passo a passo. Este construtor é independente de outros objetos.
Vantagens do Builder Pattern
Ele fornece uma separação clara e uma camada única entre a construção e a representação de um objeto especificado criado pela classe.
Ele fornece melhor controle sobre o processo de construção do padrão criado.
Fornece o cenário perfeito para alterar a representação interna dos objetos.
Como implementar o padrão do construtor?
Nesta seção, aprenderemos como implementar o padrão do construtor.
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()
Resultado
O programa acima gera a seguinte saída -
O padrão de projeto de protótipo ajuda a ocultar a complexidade das instâncias criadas pela classe. O conceito do objeto existente será diferente daquele do novo objeto, que é criado do zero.
O objeto recém-copiado pode ter algumas alterações nas propriedades, se necessário. Essa abordagem economiza tempo e recursos que vão para o desenvolvimento de um produto.
Como implementar um padrão de protótipo?
Vamos agora ver como implementar um padrão de protótipo.
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()
Resultado
O programa acima irá gerar a seguinte saída -
A saída ajuda na criação de novos objetos com os existentes e é claramente visível na saída mencionada acima.
O padrão de design de fachada fornece uma interface unificada para um conjunto de interfaces em um subsistema. Ele define uma interface de nível superior que qualquer subsistema pode usar.
Uma classe de fachada sabe qual subsistema é responsável por uma solicitação.
Como projetar um padrão de fachada?
Vamos agora ver como projetar um padrão de fachada.
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()
Resultado
O programa acima gera a seguinte saída -
Explicação
Este programa é projetado com um cenário. É ligar o motor de um carro ou de qualquer veículo em movimento. Se você observar o código, ele inclui as funções associadas para dirigir, estacionar e consumir combustível.
O Padrão de Comando adiciona um nível de abstração entre as ações e inclui um objeto, que invoca essas ações.
Nesse padrão de design, o cliente cria um objeto de comando que inclui uma lista de comandos a serem executados. O objeto de comando criado implementa uma interface específica.
A seguir está a arquitetura básica do padrão de comando -
Como implementar o padrão de comando?
Agora veremos como implementar o padrão de design.
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)
Resultado
O programa acima gera a seguinte saída -
Explicação
A saída implementa todos os comandos e palavras-chave listados na linguagem Python. Ele imprime os valores necessários das variáveis.
O padrão do adaptador funciona como uma ponte entre duas interfaces incompatíveis. Esse tipo de padrão de design vem sob o padrão estrutural, pois esse padrão combina a capacidade de duas interfaces independentes.
Este padrão envolve uma única classe, que é responsável por unir funcionalidades de interfaces independentes ou incompatíveis. Um exemplo da vida real poderia ser o caso de um leitor de cartão, que atua como um adaptador entre o cartão de memória e um laptop. Você conecta o cartão de memória no leitor de cartão e o leitor de cartão no laptop para que o cartão de memória possa ser lido no laptop.
O padrão de design do adaptador ajuda a trabalhar as classes juntas. Ele converte a interface de uma classe em outra interface com base no requisito. O padrão inclui uma especiação, um polimorfismo que nomeia um nome e várias formas. Digamos para uma classe de forma que pode ser usada de acordo com os requisitos reunidos.
Existem dois tipos de padrão de adaptador -
Padrão Adaptador de Objeto
Este padrão de design depende da implementação do objeto. Conseqüentemente, é chamado de Padrão Adaptador de Objetos.
Padrão Adaptador de Classe
Esta é uma maneira alternativa de implementar o padrão de design do adaptador. O padrão pode ser implementado usando várias heranças.
Como implementar o padrão do adaptador?
Vamos agora ver como implementar o padrão do adaptador.
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()
Resultado
O programa acima gera a seguinte saída -
Explicação
O código inclui interface do adaptador com vários parâmetros e atributos. Inclui o Adaptee junto com a interface de destino que implementa todos os atributos e exibe a saída como visível.
O padrão Decorator permite que um usuário adicione nova funcionalidade a um objeto existente sem alterar sua estrutura. Esse tipo de padrão de design vem sob o padrão estrutural, pois esse padrão atua como um invólucro para a classe existente.
Esse padrão cria uma classe decoradora, que envolve a classe original e fornece funcionalidade adicional, mantendo a assinatura dos métodos da classe intacta.
O motivo de um padrão de decorador é atribuir responsabilidades adicionais de um objeto de forma dinâmica.
Como implementar o padrão de design do decorador
O código mencionado abaixo é uma demonstração simples de como implementar o padrão de design do decorador em Python. A ilustração envolve a demonstração de uma cafeteria em formato de aula. A classe de café criada é abstrata, o que significa que não pode ser instanciada.
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'
A implementação da classe abstrata da cafeteria é feita com um arquivo separado conforme mencionado abaixo -
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()))
Resultado
O programa acima gera a seguinte saída -
O padrão de design do proxy inclui um novo objeto, que é denominado “Proxy” no lugar de um objeto existente denominado “Sujeito Real”. O objeto proxy criado do sujeito real deve estar na mesma interface, de forma que o cliente não tenha nenhuma idéia de que o proxy é usado no lugar do objeto real. As solicitações geradas pelo cliente ao proxy são passadas pelo sujeito real.
A representação UML do padrão de proxy é a seguinte -
Como implementar o padrão de proxy?
Vamos agora ver como implementar o padrão de 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
Resultado
O programa acima gera a seguinte saída -
O design do padrão de proxy ajuda a replicar as imagens que criamos. A função display_image () ajuda a verificar se os valores estão sendo impressos no prompt de comando.
O padrão de cadeia de responsabilidade é usado para obter acoplamento fraco no software, onde uma solicitação específica do cliente é passada por uma cadeia de objetos incluídos nela. Ajuda na construção de uma cadeia de objetos. A solicitação entra de uma extremidade e se move de um objeto para outro.
Esse padrão permite que um objeto envie um comando sem saber qual objeto tratará a solicitação.
Como implementar o padrão da cadeia de responsabilidade?
Veremos agora como implementar o padrão da cadeia de responsabilidade.
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)
Resultado
O programa acima gera a seguinte saída -
Explicação
O código acima cria um relatório de tarefas mensais, onde envia comandos por meio de cada função. São necessários dois manipuladores - para PDF e para texto. Ele imprime a saída assim que o objeto requerido executa cada função.
Nesse padrão, os objetos são representados como observadores que aguardam o disparo de um evento. Um observador se conecta ao assunto assim que o evento especificado ocorre. Conforme o evento ocorre, o sujeito diz aos observadores que ele ocorreu.
O diagrama UML a seguir representa o padrão do observador -
Como implementar o padrão do observador?
Vamos agora ver como implementar o padrão do observador.
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()
Resultado
O programa acima gera a seguinte saída -
Explicação
O código acima explica o procedimento de download de um determinado resultado. De acordo com a lógica do padrão do observador, todo objeto é tratado como observador. Ele imprime a saída quando o evento é disparado.
Ele fornece um módulo para máquinas de estado, que são implementadas usando subclasses, derivadas de uma classe de máquina de estado especificada. Os métodos são independentes de estado e causam transições declaradas usando decoradores.
Como implementar o padrão de estado?
A implementação básica do padrão de estado é mostrada abaixo -
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)
Resultado
O programa acima gera a seguinte saída -
O padrão de estratégia é um tipo de padrão de comportamento. O objetivo principal do padrão de estratégia é permitir que o cliente escolha entre diferentes algoritmos ou procedimentos para concluir a tarefa especificada. Diferentes algoritmos podem ser trocados sem complicações para a tarefa mencionada.
Esse padrão pode ser usado para melhorar a flexibilidade quando recursos externos são acessados.
Como implementar o padrão de estratégia?
O programa mostrado abaixo ajuda na implementação do padrão de estratégia.
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()
Resultado
O programa acima gera a seguinte saída -
Explicação
Ele fornece uma lista de estratégias das funções que executam a saída. O foco principal desse padrão de comportamento é o comportamento.
Um padrão de template define um algoritmo básico em uma classe base usando operação abstrata onde as subclasses substituem o comportamento concreto. O padrão de modelo mantém o esboço do algoritmo em um método separado. Este método é conhecido como método de modelo.
A seguir estão os diferentes recursos do padrão de modelo -
Ele define o esqueleto do algoritmo em uma operação
Inclui subclasses, que redefinem certas etapas de um 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()
Resultado
O programa acima gera a seguinte saída -
Explicação
Este código cria um modelo para preparar a refeição. Aqui, cada parâmetro representa o atributo para criar uma parte da refeição, como chá, pizza, etc.
A saída representa a visualização dos atributos.
O patterb flyweight está incluído na categoria de padrões de projeto estrutural. Ele fornece uma maneira de diminuir a contagem de objetos. Inclui vários recursos que ajudam a melhorar a estrutura do aplicativo. A característica mais importante dos objetos flyweight é imutável. Isso significa que eles não podem ser modificados depois de construídos. O padrão usa um HashMap para armazenar objetos de referência.
Como implementar o padrão flyweight?
O programa a seguir ajuda na implementação do padrão flyweight -
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()
Resultado
O programa acima gera a seguinte saída -
O padrão de fábrica abstrato também é chamado de fábrica de fábricas. Este padrão de design vem na categoria de padrão de design criativo. Ele fornece uma das melhores maneiras de criar um objeto.
Inclui uma interface, que é responsável por criar objetos relacionados ao Factory.
Como implementar o padrão de fábrica abstrato?
O programa a seguir ajuda a implementar o padrão abstrato de fábrica.
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())
Resultado
O programa acima gera a seguinte saída -
Explicação
No programa acima, a fábrica abstrata cria objetos para cada janela. Ele chama cada método, que executa a saída conforme o esperado.
O padrão orientado a objetos é o padrão mais comumente usado. Esse padrão pode ser encontrado em quase todas as linguagens de programação.
Como implementar o padrão orientado a objetos?
Vamos agora ver como implementar o padrão orientado a objetos.
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))
Resultado
O programa acima gera a seguinte saída
Explicação
O código inclui atributo de classe e atributos de instância, que são impressos de acordo com o requisito da saída. Existem vários recursos que fazem parte do padrão orientado a objetos. Os recursos são explicados no próximo capítulo.
Neste capítulo, vamos nos concentrar em padrões usando conceitos orientados a objetos e sua implementação em Python. Quando projetamos nossos programas em torno de blocos de instruções, que manipulam os dados em torno de funções, isso é chamado de programação orientada a procedimentos. Na programação orientada a objetos, existem duas instâncias principais chamadas classes e objetos.
Como implementar classes e variáveis de objeto?
A implementação de classes e variáveis de objeto são as seguintes -
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()
Resultado
O programa acima gera a seguinte saída -
Explicação
Esta ilustração ajuda a demonstrar a natureza das variáveis de classe e objeto.
“População” pertence à classe “Robô”. Portanto, é referido como uma variável de classe ou objeto.
Aqui, nos referimos à variável de classe de população como Robot.population e não como self.population.
O padrão de design do iterador se enquadra na categoria de padrões de design comportamental. Os desenvolvedores encontram o padrão iterador em quase todas as linguagens de programação. Esse padrão é usado de forma que ajuda a acessar os elementos de uma coleção (classe) de maneira sequencial, sem compreender o design da camada subjacente.
Como implementar o padrão iterador?
Veremos agora como implementar o padrão iterador.
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")
Resultado
O programa acima gera a seguinte saída -
Se você focar no padrão, a série Fibonacci é impressa com o padrão do iterador. Na rescisão forçada do usuário, a seguinte saída é impressa -
Explicação
Este código python segue o padrão do iterador. Aqui, os operadores de incremento são usados para iniciar a contagem. A contagem termina com o encerramento forçado do usuário.
Os dicionários são as estruturas de dados, que incluem uma combinação de valores-chave. Eles são amplamente usados no lugar de JSON - JavaScript Object Notation. Dicionários são usados para programação API (Interface de Programação de Aplicativo). Um dicionário mapeia um conjunto de objetos para outro conjunto de objetos. Os dicionários são mutáveis; isso significa que eles podem ser alterados conforme e quando necessário com base nos requisitos.
Como implementar dicionários em Python?
O programa a seguir mostra a implementação básica de dicionários em Python, desde sua criação até sua implementação.
# 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)
Resultado
O programa acima gera a seguinte saída -
Note −Existem desvantagens relacionadas à implementação de dicionários em Python.
Recua
Os dicionários não suportam a operação de sequência dos tipos de dados de sequência, como strings, tuplas e listas. Eles pertencem ao tipo de mapeamento integrado.
A estrutura de dados Lists é um tipo de dados versátil em Python, que pode ser escrito como uma lista de valores separados por vírgulas entre colchetes.
Sintaxe
Aqui está a sintaxe básica para a estrutura -
List_name = [ elements ];
Se você observar, a sintaxe é declarada como matrizes, com a única diferença de que as listas podem incluir elementos com diferentes tipos de dados. Os arrays incluem elementos do mesmo tipo de dados. Uma lista pode conter uma combinação de strings, inteiros e objetos. As listas podem ser usadas para a implementação de pilhas e filas.
As listas são mutáveis. Eles podem ser alterados conforme e quando necessário.
Como implementar listas?
O programa a seguir mostra as implementações de listas -
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])
Resultado
O programa acima gera a seguinte saída -
As funções integradas das listas Python são as seguintes -
Append()- Adiciona elemento ao final da lista.
Extend()- Adiciona elementos da lista a outra lista.
Insert()- Insere um item no índice definido.
Remove()- Exclui o elemento da lista especificada.
Reverse()- Inverte os elementos da lista.
sort() - Ajuda a classificar os elementos em ordem cronológica.
Um conjunto pode ser definido como uma coleção não ordenada iterável, mutável e não há inclusão de elementos duplicados nela. Em Python, a classe de conjunto é uma notação de conjunto matemático. A principal vantagem de usar um conjunto é que inclui um método altamente otimizado para verificar um elemento específico.
Python inclui uma categoria separada chamada conjuntos congelados. Esses conjuntos são objetos imutáveis que suportam apenas métodos e operadores que produzem um resultado necessário.
Como implementar conjuntos?
O programa a seguir ajuda na implementação de conjuntos -
# 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)
Resultado
O programa acima gera a seguinte saída -
O conjunto congelado pode ser demonstrado usando o seguinte programa -
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)
Resultado
O programa acima gera a seguinte saída -
Fila é uma coleção de objetos que definem uma estrutura de dados simples seguindo os procedimentos FIFO (Fast In Fast Out) e LIFO (Last In First Out). As operações de inserção e exclusão são referidas comoenqueue e dequeue operações.
As filas não permitem acesso aleatório aos objetos que contêm.
Como implementar o procedimento FIFO?
O seguinte programa auxilia na implementação do 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()
Resultado
O programa acima gera a seguinte saída -
Como implementar o procedimento LIFO?
O programa a seguir ajuda na implementação do procedimento 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()
Resultado
O programa acima gera a seguinte saída -
O que é uma fila prioritária?
Fila de prioridade é uma estrutura de dados de contêiner que gerencia um conjunto de registros com as chaves ordenadas para fornecer acesso rápido ao registro com a menor ou a maior chave na estrutura de dados especificada.
Como implementar uma fila prioritária?
A implementação da fila de prioridade é a seguinte -
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
Resultado
O programa acima gera a seguinte saída -
A serialização de string é o processo de escrever um estado de objeto em um fluxo de bytes. Em python, a biblioteca “pickle” é usada para habilitar a serialização. Este módulo inclui um algoritmo poderoso para serializar e desserializar uma estrutura de objeto Python. “Pickling” é o processo de conversão da hierarquia de objetos Python em fluxo de bytes e “unpickling” é o procedimento inverso.
A demonstração do módulo de decapagem é a seguinte -
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)
Resultado
O programa acima gera a seguinte saída -
A simultaneidade costuma ser mal interpretada como paralelismo. A simultaneidade implica programar código independente para ser executado de maneira sistemática. Este capítulo enfoca a execução de simultaneidade para um sistema operacional usando Python.
O programa a seguir ajuda na execução de simultaneidade para um sistema operacional -
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)
Resultado
O programa acima gera a seguinte saída -
Explicação
“Multiprocessamento” é um pacote semelhante ao módulo de threading. Este pacote suporta simultaneidade local e remota. Devido a este módulo, os programadores têm a vantagem de usar vários processos no sistema fornecido.
Os antipadrões seguem uma estratégia em oposição aos padrões de projeto predefinidos. A estratégia inclui abordagens comuns para problemas comuns, que podem ser formalizados e geralmente considerados como uma boa prática de desenvolvimento. Normalmente, os antipadrões são opostos e indesejáveis. Antipadrões são certos padrões usados no desenvolvimento de software, considerados más práticas de programação.
Recursos importantes de anti-padrões
Vamos agora ver alguns recursos importantes dos antipadrões.
Exatidão
Esses padrões literalmente quebram seu código e fazem você fazer coisas erradas. A seguir está uma ilustração simples disso -
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))
Capacidade de Manutenção
Um programa pode ser mantido se for fácil de entender e modificar de acordo com os requisitos. O módulo de importação pode ser considerado um exemplo de sustentabilidade.
import math
x = math.ceil(y)
# or
import multiprocessing as mp
pool = mp.pool(8)
Exemplo de anti-padrão
O exemplo a seguir ajuda na demonstração de anti-padrões -
#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
Explicação
O exemplo inclui a demonstração de padrões bons e ruins para a criação de uma função em Python.
Lidar com exceções também é um critério primário de padrões de projeto. Uma exceção é um erro que ocorre durante a execução de um programa. Quando ocorre um erro específico, é importante gerar uma exceção. Isso ajuda a reduzir travamentos do programa.
Por que usar exceções?
As exceções são maneiras convenientes de lidar com erros e condições especiais em um programa. Quando um usuário pensa que o código especificado pode produzir um erro, é importante usar o tratamento de exceções.
Exemplo - Divisão por 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)
Resultado
O programa acima gera a seguinte saída -
Levantando exceções
Especificamente na programação Python, as exceções são levantadas quando o erro correspondente do código ocorre em tempo de execução. Isso pode ser levantado à força usando o“raise” palavra-chave.
Sintaxe
raise KeyboardInterrupt
Traceback (most recent call last):
...
KeyboardInterrupt