O documento descreve o padrão de projeto Strategy em Python. O padrão permite definir uma família de algoritmos, colocá-los em classes separadas e fazer com que objetos sejam capazes de trocar de estratégia dinamicamente. O documento apresenta exemplos de implementação do padrão usando classes, funções e lambdas em Python.
(2013-10-17) [LatinoWare] Automatizando o GIMP com Python
(2014-04-16) [Garoa HC] Strategy
1. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
Strategy (Design Pattern)Strategy (Design Pattern)
e seu uso com dicionário e Multitone seu uso com dicionário e Multiton
Segunda reunião em 2014 do grupo de estudos deSegunda reunião em 2014 do grupo de estudos de
Design patterns em linguagens dinâmicasDesign patterns em linguagens dinâmicas
nono
Garoa Hacker ClubeGaroa Hacker Clube
Slides com a preparação deSlides com a preparação de
Danilo J. S. BelliniDanilo J. S. Bellini
para discussão durante reuniãopara discussão durante reunião
2014-04-162014-04-16
Código dos slides disponível em:
https://github.com/danilobellini/design_patterns
2. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
ProblemaProblema
●
Muitas soluções para um mesmo problemaMuitas soluções para um mesmo problema
– Ordenação (sort), programação não-linear,Ordenação (sort), programação não-linear,
reconhecimento de padrões, otimização,reconhecimento de padrões, otimização,
processamento de sinais, …processamento de sinais, …
– Família de algoritmosFamília de algoritmos
●
Decisão em tempo de execução do algoritmo aDecisão em tempo de execução do algoritmo a
ser utilizadoser utilizado
3. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
StrategyStrategy
●
3 conceitos:3 conceitos:
– InterfaceInterface
– EstratégiasEstratégias
– Contexto (de uso)Contexto (de uso)
4. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
UML?! Muito chato! Cadê o código?UML?! Muito chato! Cadê o código?
Não é nested o suficiente?
#!/usr/bin/env python3
from abc import ABCMeta, abstractmethod
class Estratégia(metaclass=ABCMeta):
@abstractmethod
def executar(self, a, b): # Dois inteiros
pass
class Soma(Estratégia):
def executar(self, a, b):
return a + b
class Subtração(Estratégia):
def executar(self, a, b):
return a - b
class Multiplicação(Estratégia):
def executar(self, a, b):
return a * b
class Contexto:
def __init__(self, estratégia, símbolo):
self.estratégia = estratégia
self.símbolo = símbolo
def tarefa(self, a, b):
resultado = self.estratégia.executar(a, b)
args = (a, self.símbolo, b, resultado)
print("{} {} {} = {}".format(*args))
#!/usr/bin/env python3
from abc import ABCMeta, abstractmethod
class Estratégia(metaclass=ABCMeta):
@abstractmethod
def executar(self, a, b): # Dois inteiros
pass
class Soma(Estratégia):
def executar(self, a, b):
return a + b
class Subtração(Estratégia):
def executar(self, a, b):
return a - b
class Multiplicação(Estratégia):
def executar(self, a, b):
return a * b
class Contexto:
def __init__(self, estratégia, símbolo):
self.estratégia = estratégia
self.símbolo = símbolo
def tarefa(self, a, b):
resultado = self.estratégia.executar(a, b)
args = (a, self.símbolo, b, resultado)
print("{} {} {} = {}".format(*args))
if __name__ == "__main__":
Contexto(Soma(), "+").tarefa(22, 3)
ctx = Contexto(Subtração(), "-")
ctx.tarefa(22, 3)
ctx.estratégia = Multiplicação()
ctx.símbolo = "*"
ctx.tarefa(22, 3)
if __name__ == "__main__":
Contexto(Soma(), "+").tarefa(22, 3)
ctx = Contexto(Subtração(), "-")
ctx.tarefa(22, 3)
ctx.estratégia = Multiplicação()
ctx.símbolo = "*"
ctx.tarefa(22, 3)
strategy_0.py
5. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
Burocracia...é necessária?Burocracia...é necessária?
●
Definição de classes para cada algoritmoDefinição de classes para cada algoritmo
– Mais de uma instância de um único algoritmo?Mais de uma instância de um único algoritmo?
– Memória (efeito colaterais)?Memória (efeito colaterais)?
– Instante da instanciação?Instante da instanciação?
●
Definição explícita da interfaceDefinição explícita da interface
– Tipos estáticos e explícitos?Tipos estáticos e explícitos?
– Quantidades/nomes de argumentos sempreQuantidades/nomes de argumentos sempre
idênticos?idênticos?
●
Orientação a objetos?Orientação a objetos?
Não!Não!
6. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
InterfaceInterface
em Pythonem Python
●
Duck typingDuck typing
““When I see a bird thatWhen I see a bird that
●
walks like a duck andwalks like a duck and
●
swims like a duck andswims like a duck and
●
quacks like a duck,quacks like a duck,
I call that bird a duck.”I call that bird a duck.”
●
ABC (Abstract Base Classes)ABC (Abstract Base Classes)
– Dunder __subclasshook__Dunder __subclasshook__
7. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
#!/usr/bin/env python3
class Soma:
def executar(self, a, b):
return a + b
class Subtração:
def executar(self, a, b):
return a - b
class Multiplicação:
def executar(self, a, b):
return a * b
class Contexto:
def __init__(self, estratégia, símbolo):
self.estratégia = estratégia
self.símbolo = símbolo
def tarefa(self, a, b):
resultado = self.estratégia.executar(a, b)
args = (a, self.símbolo, b, resultado)
print("{} {} {} = {}".format(*args))
#!/usr/bin/env python3
class Soma:
def executar(self, a, b):
return a + b
class Subtração:
def executar(self, a, b):
return a - b
class Multiplicação:
def executar(self, a, b):
return a * b
class Contexto:
def __init__(self, estratégia, símbolo):
self.estratégia = estratégia
self.símbolo = símbolo
def tarefa(self, a, b):
resultado = self.estratégia.executar(a, b)
args = (a, self.símbolo, b, resultado)
print("{} {} {} = {}".format(*args))
if __name__ == "__main__":
Contexto(Soma(), "+").tarefa(22, 3)
ctx = Contexto(Subtração(), "-")
ctx.tarefa(22, 3)
ctx.estratégia = Multiplicação()
ctx.símbolo = "*"
ctx.tarefa(22, 3)
if __name__ == "__main__":
Contexto(Soma(), "+").tarefa(22, 3)
ctx = Contexto(Subtração(), "-")
ctx.tarefa(22, 3)
ctx.estratégia = Multiplicação()
ctx.símbolo = "*"
ctx.tarefa(22, 3)
Sem classe abstrataSem classe abstrata
(interface implícita)(interface implícita)
strategy_1.py
8. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
#!/usr/bin/env python3
from abc import ABCMeta, abstractmethod
class Estratégia(metaclass=ABCMeta):
@abstractmethod
def executar(self, a, b): # Dois inteiros
pass
@classmethod
def __subclasshook__(cls, C):
return any("executar" in vars(B) for B in C.mro()) or NotImplemented
class Soma:
def executar(self, a, b):
return a + b
print(isinstance(Soma(), Estratégia)) # True
print(issubclass(Soma, Estratégia)) # True
#!/usr/bin/env python3
from abc import ABCMeta, abstractmethod
class Estratégia(metaclass=ABCMeta):
@abstractmethod
def executar(self, a, b): # Dois inteiros
pass
@classmethod
def __subclasshook__(cls, C):
return any("executar" in vars(B) for B in C.mro()) or NotImplemented
class Soma:
def executar(self, a, b):
return a + b
print(isinstance(Soma(), Estratégia)) # True
print(issubclass(Soma, Estratégia)) # True
Subclass HookSubclass Hook subclasshook.py
In [5]: B.mro()
Out[5]: [__main__.B, __main__.A, builtins.object]
In [6]: D.mro() # MRO = Method Resolution Order
Out[6]: [__main__.D, __main__.B, __main__.C, __main__.A, builtins.object]
In [7]: vars(B) # Atributos (métodos, propriedades, etc.)
Out[7]: dict_proxy({'__module__': '__main__', '__doc__': None})
In [5]: B.mro()
Out[5]: [__main__.B, __main__.A, builtins.object]
In [6]: D.mro() # MRO = Method Resolution Order
Out[6]: [__main__.D, __main__.B, __main__.C, __main__.A, builtins.object]
In [7]: vars(B) # Atributos (métodos, propriedades, etc.)
Out[7]: dict_proxy({'__module__': '__main__', '__doc__': None})
In [1]: class A: pass
In [2]: class B(A): pass
In [3]: class C(A): pass
In [4]: class D(B, C): pass
In [1]: class A: pass
In [2]: class B(A): pass
In [3]: class C(A): pass
In [4]: class D(B, C): pass
O que é MRO?
9. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
EstratégiaEstratégia
●
Qualquer callableQualquer callable
– Método, função, __call__, operadores, etc.Método, função, __call__, operadores, etc.
●
Funções como objetos de segunda classeFunções como objetos de segunda classe
– Utilização do método de um objetosUtilização do método de um objetos
– Classes para possibilitar objetosClasses para possibilitar objetos
– InstanciaçãoInstanciação
●
Python, Ruby, JavaScript, …Python, Ruby, JavaScript, …
– Funções de primeira classeFunções de primeira classe
– Funções de ordem superiorFunções de ordem superior
– Fechamentos (closures)Fechamentos (closures)
10. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
#!/usr/bin/env python3
def soma(a, b):
return a + b
def subtração(a, b):
return a - b
def multiplicação(a, b):
return a * b
class Contexto:
def __init__(self, estratégia, símbolo):
self.estratégia = estratégia
self.símbolo = símbolo
def tarefa(self, a, b):
resultado = self.estratégia(a, b)
args = (a, self.símbolo, b, resultado)
print("{} {} {} = {}".format(*args))
#!/usr/bin/env python3
def soma(a, b):
return a + b
def subtração(a, b):
return a - b
def multiplicação(a, b):
return a * b
class Contexto:
def __init__(self, estratégia, símbolo):
self.estratégia = estratégia
self.símbolo = símbolo
def tarefa(self, a, b):
resultado = self.estratégia(a, b)
args = (a, self.símbolo, b, resultado)
print("{} {} {} = {}".format(*args))
if __name__ == "__main__":
Contexto(soma, "+").tarefa(22, 3)
ctx = Contexto(subtração, "-")
ctx.tarefa(22, 3)
ctx.estratégia = multiplicação
ctx.símbolo = "*"
ctx.tarefa(22, 3)
if __name__ == "__main__":
Contexto(soma, "+").tarefa(22, 3)
ctx = Contexto(subtração, "-")
ctx.tarefa(22, 3)
ctx.estratégia = multiplicação
ctx.símbolo = "*"
ctx.tarefa(22, 3)
Funções de primeira classe!Funções de primeira classe!
strategy_2.py
●
Funções comoFunções como
valores (ou objetos)valores (ou objetos)
●
““Callback”Callback”
●
““Handler”Handler”
11. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
PythonPython
lambda e namedtuplelambda e namedtuple
#!/usr/bin/env python3
from collections import namedtuple
Strategy = namedtuple("Strategy", ["func", "symbol"])
sum = lambda a, b: a + b
sub = lambda a, b: a - b
mul = lambda a, b: a * b
apply = lambda st, a, b: st.func(a, b)
strategies = [Strategy(sum, "+"), Strategy(sub, "-"), Strategy(mul, "*")]
for st in strategies:
print("2 %c 3 = %d" % (st.symbol, apply(st, 2, 3)))
print("7 %c 5 = %d" % (st.symbol, apply(st, 7, 5)))
#!/usr/bin/env python3
from collections import namedtuple
Strategy = namedtuple("Strategy", ["func", "symbol"])
sum = lambda a, b: a + b
sub = lambda a, b: a - b
mul = lambda a, b: a * b
apply = lambda st, a, b: st.func(a, b)
strategies = [Strategy(sum, "+"), Strategy(sub, "-"), Strategy(mul, "*")]
for st in strategies:
print("2 %c 3 = %d" % (st.symbol, apply(st, 2, 3)))
print("7 %c 5 = %d" % (st.symbol, apply(st, 7, 5)))
strategy_3.py
12. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
CC
#include <stdio.h>
typedef int (*BinaryOpPtr)(int, int);
typedef struct{
BinaryOpPtr func;
char symbol;
} Strategy;
int sum(int a, int b){ return a + b; }
int sub(int a, int b){ return a - b; }
int mul(int a, int b){ return a * b; }
int apply(Strategy st, int a, int b){
return st.func(a, b);
}
Strategy strategies[] = {{sum, '+'}, {sub, '-'}, {mul, '*'}};
int main(){
Strategy st;
int idx;
for(idx = 0; idx < 3; idx++){
st = strategies[idx];
printf("2 %c 3 = %dn", st.symbol, apply(st, 2, 3));
printf("7 %c 5 = %dn", st.symbol, apply(st, 7, 5));
}
return 0;
}
#include <stdio.h>
typedef int (*BinaryOpPtr)(int, int);
typedef struct{
BinaryOpPtr func;
char symbol;
} Strategy;
int sum(int a, int b){ return a + b; }
int sub(int a, int b){ return a - b; }
int mul(int a, int b){ return a * b; }
int apply(Strategy st, int a, int b){
return st.func(a, b);
}
Strategy strategies[] = {{sum, '+'}, {sub, '-'}, {mul, '*'}};
int main(){
Strategy st;
int idx;
for(idx = 0; idx < 3; idx++){
st = strategies[idx];
printf("2 %c 3 = %dn", st.symbol, apply(st, 2, 3));
printf("7 %c 5 = %dn", st.symbol, apply(st, 7, 5));
}
return 0;
}
O mesmo
exemplo do
slide
anterior
strategy.c
13. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
ScipyScipy
(e muitos outros)(e muitos outros)
●
Duas maneiras diferentes de resolver o problema:Duas maneiras diferentes de resolver o problema:
– Diversas funções dispersas com assinatura similar, usar noDiversas funções dispersas com assinatura similar, usar no
contextocontexto
●
e.g. funções do scipy.optimizee.g. funções do scipy.optimize
– String com o nome da estratégia como parâmetroString com o nome da estratégia como parâmetro
●
e.g. projeto de filtros IIR com o scipy.signal.iirdesigne.g. projeto de filtros IIR com o scipy.signal.iirdesign
– ftype = “ellip”ftype = “ellip” → Elíptico→ Elíptico
– ftype = “butter”ftype = “butter” → Butterworth→ Butterworth
– ftype = “cheby1”ftype = “cheby1” → Chebyshev I→ Chebyshev I
– ftype = “cheby2”ftype = “cheby2” → Chebyshev II→ Chebyshev II
– ftype = “bessel”ftype = “bessel” → Bessel→ Bessel
– Saída chaveada pela stringSaída chaveada pela string “ba”“ba” ouou “zpk”“zpk” no parâmetro de entradano parâmetro de entrada outputoutput
Em alguns casos (e.g. fmin), é possível
usar os nomes com o built-in dir para
possíveis consultas
Estratégias existentes
apresentadas em docstring
14. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
ContextoContexto
●
Completamente aberto, basta que utilize ouCompletamente aberto, basta que utilize ou
possa utilizar a estratégiapossa utilizar a estratégia
– ““Executa o algoritmo”Executa o algoritmo”
●
Outros possíveis requisitos, reflection “CRUD”:Outros possíveis requisitos, reflection “CRUD”:
– Conhecer/consultar todas as estratégiasConhecer/consultar todas as estratégias
– Varrer por todas as estratégiasVarrer por todas as estratégias
– Modificar, remover ou criar novas estratégiasModificar, remover ou criar novas estratégias
15. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
DicionárioDicionário
(Mapping / Hash / Vetor associativo)(Mapping / Hash / Vetor associativo)
●
Pares chave-valorPares chave-valor
●
Sem “ordenação”Sem “ordenação”
●
VariantesVariantes
– OrderedDictOrderedDict
– defaultdictdefaultdict
●
3 métodos para iterar:3 métodos para iterar:
– Dict.keys()Dict.keys()
– Dict.values()Dict.values()
– Dict.items()Dict.items() → Pares chave, valor→ Pares chave, valor
#!/usr/bin/env python3
strategies = {
"+": lambda a, b: a + b,
"-": lambda a, b: a - b,
"*": lambda a, b: a * b,
}
for key, value in strategies.items():
print("2 %c 3 = %d" % (key, value(2, 3)))
print("7 %c 5 = %d" % (key, value(7, 5)))
#!/usr/bin/env python3
strategies = {
"+": lambda a, b: a + b,
"-": lambda a, b: a - b,
"*": lambda a, b: a * b,
}
for key, value in strategies.items():
print("2 %c 3 = %d" % (key, value(2, 3)))
print("7 %c 5 = %d" % (key, value(7, 5)))
strategy_4.py
No Python 3, devolvem
iteráveis. No Python 2,
devolvem listas, mas os
métodos com prefixo “iter”
(e.g. “dict.iteritems()”)
devolvem iteradores.
Função
(anônima)
como valor
16. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
E quando o elemento com aE quando o elemento com a
“chave” não está no dicionário?“chave” não está no dicionário?
●
__missing____missing__
– Criar elemento?Criar elemento?
– Responder?Responder?
●
Há análogos:Há análogos:
– __getitem____getitem__
– __getattr____getattr__
#!/usr/bin/env python3
class MeuDicionário(dict):
def __missing__(self, chave):
if chave.strip() != chave:
valor = self[chave.strip()]
self[chave] = valor
return valor
raise KeyError("Not Found")
estratégias = MeuDicionário([
("+", lambda a, b: a + b),
("-", lambda a, b: a - b),
("*", lambda a, b: a * b),
])
for símbolo in ["+", " +", " - ", "n* n"]:
função = estratégias[símbolo]
print("2 %s 3 = %d" % (símbolo, função(2, 3)))
print("7 %s 5 = %d" % (símbolo, função(7, 5)))
print(estratégias["/"])
#!/usr/bin/env python3
class MeuDicionário(dict):
def __missing__(self, chave):
if chave.strip() != chave:
valor = self[chave.strip()]
self[chave] = valor
return valor
raise KeyError("Not Found")
estratégias = MeuDicionário([
("+", lambda a, b: a + b),
("-", lambda a, b: a - b),
("*", lambda a, b: a * b),
])
for símbolo in ["+", " +", " - ", "n* n"]:
função = estratégias[símbolo]
print("2 %s 3 = %d" % (símbolo, função(2, 3)))
print("7 %s 5 = %d" % (símbolo, função(7, 5)))
print(estratégias["/"])
missing.py
17. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
MultitonMultiton
●
Multi + singletonMulti + singleton
– ““Registro deRegistro de
singletons”singletons”
– LazyLazy
●
Similar aoSimilar ao
dicionáriodicionário
– Valores definidosValores definidos
(ou instanciados)(ou instanciados)
no primeiro usono primeiro uso
●
““Cache”Cache”
#!/usr/bin/env python3
op = {
"+": lambda a, b: a + b,
"-": lambda a, b: a - b,
"*": lambda a, b: a * b,
}
class MeuDicionário(dict):
def __missing__(self, chave):
if chave[0] in op:
b = int(chave[1:])
func = op[chave[0]]
resultado = lambda a: func(a, b)
else:
a = int(chave[:-1])
func = op[chave[-1]]
resultado = lambda b: func(a, b)
self[chave] = resultado
return resultado
estratégias = MeuDicionário()
for símbolo in ["+2", "5-", "-3", "4*", "+2"]:
função = estratégias[símbolo]
print("2, %s -> %d" % (símbolo, função(2)))
print("-1, %s -> %d" % (símbolo, função(-1)))
print("7, %s -> %d" % (símbolo, função(7)))
#!/usr/bin/env python3
op = {
"+": lambda a, b: a + b,
"-": lambda a, b: a - b,
"*": lambda a, b: a * b,
}
class MeuDicionário(dict):
def __missing__(self, chave):
if chave[0] in op:
b = int(chave[1:])
func = op[chave[0]]
resultado = lambda a: func(a, b)
else:
a = int(chave[:-1])
func = op[chave[-1]]
resultado = lambda b: func(a, b)
self[chave] = resultado
return resultado
estratégias = MeuDicionário()
for símbolo in ["+2", "5-", "-3", "4*", "+2"]:
função = estratégias[símbolo]
print("2, %s -> %d" % (símbolo, função(2)))
print("-1, %s -> %d" % (símbolo, função(-1)))
print("7, %s -> %d" % (símbolo, função(7)))
multiton.py
Closure
18. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
AudioLazyAudioLazy
●
StrategyDict (dicionário de estratégias)StrategyDict (dicionário de estratégias)
– IterávelIterável
●
Padrão por estratégias (valores)Padrão por estratégias (valores)
– Múltiplas chaves (nomes)Múltiplas chaves (nomes)
●
e.g.e.g. window[“rectangular”] is window[“rect”]window[“rectangular”] is window[“rect”] → True→ True
– Acesso como atributosAcesso como atributos
●
e.g.e.g. lowpass.pole_exp(pi/7)lowpass.pole_exp(pi/7)
– Estratégia padrão do dicionárioEstratégia padrão do dicionário
●
Consultável no atributo “default”Consultável no atributo “default”
●
e.g.e.g. lowpass(pi/7)lowpass(pi/7) equivale aequivale a lowpass.pole(pi/7)lowpass.pole(pi/7)
Docstrings com
“resumos”
automáticos das
docstrings das
estratégias
19. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
Uso da StrategyDict na AudioLazyUso da StrategyDict na AudioLazy
In [1]: import audiolazy
In [2]: from audiolazy import StrategyDict
In [3]: [name for name in dir(audiolazy)
...: if isinstance(getattr(audiolazy, name), StrategyDict)]
Out[3]:
['accumulate',
'almost_eq',
'chain',
'chunks',
'comb',
'envelope',
'erb',
'float_str',
'gammatone',
'highpass',
'izip',
'lagrange',
'lowpass',
'lpc',
'maverage',
'resonator',
'window']
In [4]: len(_) # Total de nomes de instâncias de StrategyDict na AudioLazy
Out[4]: 17
In [5]: len(audiolazy.window) # Todos atualmente com pelo menos 2 estratégias
Out[5]: 6
In [1]: import audiolazy
In [2]: from audiolazy import StrategyDict
In [3]: [name for name in dir(audiolazy)
...: if isinstance(getattr(audiolazy, name), StrategyDict)]
Out[3]:
['accumulate',
'almost_eq',
'chain',
'chunks',
'comb',
'envelope',
'erb',
'float_str',
'gammatone',
'highpass',
'izip',
'lagrange',
'lowpass',
'lpc',
'maverage',
'resonator',
'window']
In [4]: len(_) # Total de nomes de instâncias de StrategyDict na AudioLazy
Out[4]: 17
In [5]: len(audiolazy.window) # Todos atualmente com pelo menos 2 estratégias
Out[5]: 6
20. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
strategy_sort.py
#!/usr/bin/env python3
from operator import itemgetter
from audiolazy import StrategyDict
sort = StrategyDict("sort")
@sort.strategy("slow", "bad")
def sort(data):
for idx, el in enumerate(data):
idx_min, el_min = min(enumerate(data[idx:], idx), key=itemgetter(1))
data[idx], data[idx_min] = el_min, el
@sort.strategy("bubble")
def sort(data):
. . .
@sort.strategy("merge")
def sort(data):
. . .
#!/usr/bin/env python3
from operator import itemgetter
from audiolazy import StrategyDict
sort = StrategyDict("sort")
@sort.strategy("slow", "bad")
def sort(data):
for idx, el in enumerate(data):
idx_min, el_min = min(enumerate(data[idx:], idx), key=itemgetter(1))
data[idx], data[idx_min] = el_min, el
@sort.strategy("bubble")
def sort(data):
. . .
@sort.strategy("merge")
def sort(data):
. . .
if __name__ == "__main__":
from random import shuffle
data = list(range(30))
print(sort.default.__name__) # slow (primeira)
print()
print(sort.bubble is sort["bubble"]) # True
print()
print(sort) # As 3 estratégias
for st in sort:
print()
shuffle(data)
print(data) # Scrambled
st(data)
print(data) # [0, 1, 2, ...]
if __name__ == "__main__":
from random import shuffle
data = list(range(30))
print(sort.default.__name__) # slow (primeira)
print()
print(sort.bubble is sort["bubble"]) # True
print()
print(sort) # As 3 estratégias
for st in sort:
print()
shuffle(data)
print(data) # Scrambled
st(data)
print(data) # [0, 1, 2, ...]
Contexto
Exemplo: Ordenação com um StrategyDict
● “slow”: Ordenar coletando valores mínimos
● “bubble”: Alone bubble sort
● “merge”: Merge sort
21. 2014-04-16 – Strategy – Design patterns em linguagens dinâmicas – Danilo J. S. Bellini
Fim!Fim!
Obrigado =)
Repositório com o código dos slides:
https://github.com/danilobellini/design_patterns