Danilo de Jesus da Silva Bellini

Propaganda
Tutorial
Adaptatividade
em
Python
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Python
●
Multiparadigma
●
Uso geral (científico, GUI, Web, games, etc.)
●
Metaprogramação e reflexão
–
●
“Python is more dynamic, does less error-checking”
(P. Norvig, ao comparar Python com LISP)
Em tempo de execução...
–
Código (arquivos/strings)
–
AST
–
Bytecode
!
s
i
a
m
o
t
i
u
E m =)
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Parte 1
Geradores,
iteradores e
iteráveis
“Talk is cheap. Show me the code.”
(Linus Torvalds)
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Avaliação tardia
(deferred) e geradores
●
●
●
●
Yield
–
Return-like
–
Estado “suspenso”
Avaliação no uso, não na
declaração
“Fluxo de controle” em um
objeto
Iteráveis sem tamanho definido
–
I/O
–
“Algoritmo” sem término
definido?
## Função
Função geradora
geradora
def
def count(start=0,
count(start=0, step=1):
step=1):
while
True:
while True:
yield
yield start
start
start
+=
start += step
step
## Geradores
Geradores são
são iteradores
iteradores
gen
=
count()
gen = count()
next(gen)
next(gen)
next(gen)
next(gen)
next(gen)
next(gen)
gen_impares
gen_impares == count(1,
count(1, step=2)
step=2)
next(gen_impares)
next(gen_impares)
next(gen_impares)
next(gen_impares)
next(gen_impares)
next(gen_impares)
next(gen)
next(gen)
## Expressão
Expressão geradora
geradora
gg == (el
(el **
** 22 for
for el
el in
in count(3)
count(3)
if
el
%
3
==
if el % 3 == 0)
0)
next(g)
next(g)
next(g)
next(g)
next(g)
next(g)
?!? # Iteradores são iteráveis
# Iteradores são iteráveis
for
for el
el in
in count(5,
count(5, 3):
3):
print(el)
o:
t
print(el)
n
if
pro nt
if el
el >=
>= 30:
30:
m
te s.cou
break
o
s
break
ol
Is
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
to
iter
In
In [1]:
[1]: def
def count(start=0,
count(start=0, step=1):
step=1):
...:
while
True:
...:
while True:
...:
yield
...:
yield start
start
...:
start
+=
...:
start += step
step
...:
...:
In
In [11]:
[11]: gg == (el
(el **
** 22 for
for el
el in
in count(3)
count(3)
...:
if
el
%
3
==
...:
if el % 3 == 0)
0)
...:
...:
In
In [2]:
[2]: gen
gen == count()
count()
In
In [12]:
[12]: next(g)
next(g)
Out[12]:
9
Out[12]: 9
In
In [3]:
[3]: next(gen)
next(gen)
Out[3]:
0
Out[3]: 0
In
In [13]:
[13]: next(g)
next(g)
Out[13]:
36
Out[13]: 36
In
In [4]:
[4]: next(gen)
next(gen)
Out[4]:
1
Out[4]: 1
In
In [14]:
[14]: next(g)
next(g)
Out[14]:
81
Out[14]: 81
In
In [15]:
[15]: for
for el
el in
in count(5,
count(5, 3):
3):
....:
print(el)
....:
print(el)
....:
if
....:
if el
el >=
>= 30:
30:
....:
break
In
[6]:
gen_impares
=
count(1,
step=2)
....:
break
In [6]: gen_impares = count(1, step=2)
....:
....:
5
In
[7]:
next(gen_impares)
5
In [7]: next(gen_impares)
8
Out[7]:
8
Out[7]: 11
11
11
14
In
14
In [8]:
[8]: next(gen_impares)
next(gen_impares)
17
Out[8]:
3
17
Out[8]: 3
20
20
23
In
[9]:
next(gen_impares)
23
In [9]: next(gen_impares)
26
Out[9]:
26
Out[9]: 55
29
29
32
In
[10]:
next(gen)
32
In [10]: next(gen)
Out[10]:
3
Out[10]: 3
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
In
In [5]:
[5]: next(gen)
next(gen)
Out[5]:
2
Out[5]: 2
from
from collections
collections import
import Iterator
Iterator
class
class Counter(Iterator):
Counter(Iterator):
def
def __init__(self,
__init__(self, start=0,
start=0, step=1):
step=1):
self.value
=
start
self.value = start
self.step
self.step == step
step
self.finish
=
self.finish = False
False
def
def next(self):
next(self):
if
if self.finish:
self.finish:
raise
raise StopIteration
StopIteration
result
=
self.value
result = self.value
self.value
self.value +=
+= self.step
self.step
return
result
return result
Iterador/iterável
com um pouco de
orientação a
objetos
__next__
__next__ == next
next ## Compatibilidade
Compatibilidade Python
Python 2/3
2/3
●
“Dunders” (Double UNDERscore)
–
__init__
●
–
__next__ (next no Python 2)
●
–
Inicializador (“construtor”)
Devolve o próximo elemento
__iter__
●
●
Iterável: Devolve um novo iterador
Iterador: Devolve a si próprio
Mudança de
comportamento do
iterável dentro de
seu laço
gg == Counter()
Counter()
next(g)
next(g)
next(g)
next(g)
g.value
g.value == 13
13
next(g)
next(g)
next(g)
next(g)
g.step
g.step == 77
next(g)
next(g)
next(g)
next(g)
next(g)
next(g)
counter
counter == Counter(start=-5,
Counter(start=-5, step=7)
step=7)
for
el
in
counter:
for el in counter:
print(el)
print(el)
counter.step
counter.step -=
-= 11
counter.finish
counter.finish == counter.value
counter.value << -10
-10
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
In
In [1]:
[1]: %paste
%paste
from
collections
from collections import
import Iterator
Iterator
## [...]
[...]
##
## --- End
End pasted
pasted text
text --In
In [2]:
[2]: gg == Counter()
Counter()
In
In [3]:
[3]: next(g)
next(g)
Out[3]:
Out[3]: 00
In
In [4]:
[4]: next(g)
next(g)
Out[4]:
1
Out[4]: 1
In
In [5]:
[5]: g.value
g.value == 13
13
In
In [6]:
[6]: next(g)
next(g)
Out[6]:
13
Out[6]: 13
In
In [7]:
[7]: next(g)
next(g)
Out[7]:
14
Out[7]: 14
In
In [8]:
[8]: g.step
g.step == 77
In
In [9]:
[9]: next(g)
next(g)
Out[9]:
15
Out[9]: 15
In
In [10]:
[10]: next(g)
next(g)
Out[10]:
22
Out[10]: 22
Classe
“Counter”
In
In [12]:
[12]: counter
counter == Counter(start=-5,
Counter(start=-5, step=7)
step=7)
In
In [13]:
[13]: for
for el
el in
in counter:
counter:
....:
print(el)
....:
print(el)
....:
counter.step
....:
counter.step -=
-= 11
....:
counter.finish
....:
counter.finish == counter.value
counter.value << -10
-10
....:
....:
-5
-5
22
88
13
13
17
17
## [...]
[...] Lembram
Lembram do
do Counter.next?
Counter.next?
20
20
def
next(self):
def next(self):
22
22
if
if self.finish:
self.finish:
23
23
raise
raise StopIteration
StopIteration
23
23
result
=
self.value
result = self.value
22
22
self.value
self.value +=
+= self.step
self.step
20
20
return
result
return result
17
17
13
13
88
22
-5
-5
In
next(g)
In [11]:
[11]:
next(g)
Danilo
J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Out[11]:
29
Out[11]:
29
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Lazy evaluation
Avaliação “preguiçosa”
●
“Tardia” + “cache”:
●
“Por que fazer antes o
que pode ser deixado
para a última hora?”
+
Valores computados
uma única vez
●
Uso único?
–
Único caso equivalente
à avaliação tardia
(“deferred”)
●
Iteradores/Geradores:
cópias (T)
–
itertools.tee
–
audiolazy.thub
–
Fluxo de dados e “Dataflow
programming”
Funções (+ imutabilidade):
decorators (cache)
–
functools.lru_cache
(Python 3)
–
audiolazy.cached
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
## coding:
coding: utf-8
utf-8
from
itertools
from itertools import
import count,
count, takewhile,
takewhile, tee
tee
def
def prime_gen():
prime_gen():
"""
""" Gerador
Gerador de
de números
números primos
primos """
"""
yield
yield 22
primes
primes == []
[]
for
for value
value in
in count(start=3,
count(start=3, step=2):
step=2):
iter_primes
=
takewhile(lambda
iter_primes = takewhile(lambda x:
x: xx ** xx <=
<= value,
value, primes)
primes)
if
all(value
%
p
!=
0
for
p
in
iter_primes):
if all(value % p != 0 for p in iter_primes):
primes.append(value)
1º
primes.append(value)
1º primo:
primo: 22
yield
2º
yield value
value
2º primo:
primo: 33
3º
3º primo:
primo: 55
primes,
4º
primes, primes_copy
primes_copy == tee(prime_gen(),
tee(prime_gen(), 2)
2)
4º primo:
primo: 77
5º
5º primo:
primo: 11
11
for
idx,
p
in
enumerate(primes,
1):
[...]
for idx, p in enumerate(primes, 1):
[...]
print(u"{:>5}º
primo:
{}".format(idx,
p))
198º
print(u"{:>5}º primo: {}".format(idx, p))
198º primo:
primo: 1213
1213
if
idx
==
200:
199º
primo:
1217
if idx == 200:
199º primo: 1217
break
200º
break
200º primo:
primo: 1223
1223
for
for idx,
idx, pp in
in enumerate(primes_copy,
enumerate(primes_copy, 1):
1):
print(u"{:>5}º
primo
ao
quadrado:
print(u"{:>5}º primo ao quadrado: {}".format(idx,
{}".format(idx, pp **
** 2))
2))
if
idx
==
200:
if idx == 200:
1º
1º primo
primo ao
ao quadrado:
quadrado: 44
break
break
2º
2º primo
primo ao
ao quadrado:
quadrado: 99
3º
3º primo
primo ao
ao quadrado:
quadrado: 25
25
4º
primo
ao
quadrado:
49
4º primo ao quadrado: 49
Baseado em:
5º
5º primo
primo ao
ao quadrado:
quadrado: 121
121
https://gist.github.com/danilobellini/7233352
[...]
[...]
198º
198º primo
primo ao
ao quadrado:
quadrado: 1471369
1471369
199º
primo
ao
quadrado:
1481089
199º
primo ao quadrado: 1481089
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade
em primo
Python
200º
ao
200ºe primo
ao quadrado:
quadrado: 1495729
1495729
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29
2015-01-30
## coding:
coding: utf-8
utf-8
from
audiolazy
from audiolazy import
import count,
count, takewhile,
takewhile, thub
thub
def
def prime_gen():
prime_gen():
"""
""" Gerador
Gerador de
de números
números primos
primos """
"""
yield
yield 22
primes
primes == []
[]
for
for value
value in
in count(start=3,
count(start=3, step=2):
step=2):
stream_primes
=
takewhile(lambda
stream_primes = takewhile(lambda x:
x: xx ** xx <=
<= value,
value, primes)
primes)
if
all(value
%
stream_primes
!=
0):
if all(value % stream_primes != 0):
primes.append(value)
1º
primes.append(value)
1º primo:
primo: 22
yield
2º
yield value
value
2º primo:
primo: 33
3º
3º primo:
primo: 55
primes
4º
primes == thub(prime_gen(),
thub(prime_gen(), 2)
2)
4º primo:
primo: 77
5º
5º primo:
primo: 11
11
for
idx,
p
in
enumerate(primes,
1):
[...]
for idx, p in enumerate(primes, 1):
[...]
print(u"{:>5}º
primo:
{}".format(idx,
p))
198º
print(u"{:>5}º primo: {}".format(idx, p))
198º primo:
primo: 1213
1213
if
idx
==
200:
199º
primo:
1217
if idx == 200:
199º primo: 1217
break
200º
break
200º primo:
primo: 1223
1223
for
for idx,
idx, pp in
in enumerate(primes,
enumerate(primes, 1):
1):
print(u"{:>5}º
primo
ao
quadrado:
print(u"{:>5}º primo ao quadrado: {}".format(idx,
{}".format(idx, pp **
** 2))
2))
if
idx
==
200:
if idx == 200:
1º
1º primo
primo ao
ao quadrado:
quadrado: 44
break
break
2º
2º primo
primo ao
ao quadrado:
quadrado: 99
3º
3º primo
primo ao
ao quadrado:
quadrado: 25
25
Mesma coisa, mas com
4º
primo
ao
quadrado:
49
4º primo ao quadrado: 49
audiolazy.thub no lugar de
5º
5º primo
primo ao
ao quadrado:
quadrado: 121
121
itertools.tee, e takewhile
[...]
[...]
devolvendo audiolazy.Stream
198º
198º primo
primo ao
ao quadrado:
quadrado: 1471369
1471369
199º
primo
ao
quadrado:
1481089
199º
primo ao quadrado: 1481089
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade
em primo
Python
200º
ao
200ºe primo
ao quadrado:
quadrado: 1495729
1495729
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29
2015-01-30
Outros exemplos
●
●
Geradores para I/O
–
AudioLazy: mcfm.py, robotize.py, animated_plot.py
–
Turing(1936): a-machine VS c-machine
Avaliação lazy/preguiçosa por decorator
import
import sys
sys ## Para
Para funcionar
funcionar em
em Python
Python 22 ee 33
if
if sys.version_info.major
sys.version_info.major ==
== 2:
2:
from
cachetools
import
lru_cache
from cachetools import lru_cache
else:
else:
from
from functools
functools import
import lru_cache
lru_cache
Algoritmo
para cada
valor/bloco
de “entrada”
(saída em
tempo finito);
causalidade
@lru_cache(maxsize=1000)
@lru_cache(maxsize=1000)
def
def fib(n):
fib(n):
return
return nn if
if nn <=
<= 11 else
else fib(n
fib(n -- 2)
2) ++ fib(n
fib(n -- 1)
1)
print(fib(500))
print(fib(500))
139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125
139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Parte 2
“Primeira classe” e
closures
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Design patterns?
(design strategies?)
●
Slides “Design Patterns in Dynamic Programming” (P. Norvig)
–
●
Defaults != patterns != standards != defaults
–
●
“16 of 23 patterns have qualitatively simpler implementation in Lisp or Dylan than
in C++ for at least some uses of each pattern”
http://info.abril.com.br/noticias/rede/gestao20/software/a-lingua-portuguesa-brasil
eira-e-pessima-standard-vs-pattern/
2013-2014: Grupo de estudos para discutir aplicabilidade em linguagens
dinâmicas:
–
https://garoa.net.br/wiki/Design_patterns_em_linguagens_din%C3%A2micas
–
Simplificados com funções/“tipos” de primeira classe:
●
●
Command, strategy, template method, visitor, abstract factory, factory method, flyweight,
proxy, chain of responsibility, state
Exemplos (código) em várias linguagens
–
http://en.wikibooks.org/wiki/Computer_Science_Design_Patterns
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Função de primeira classe
●
●
Funções como valores/objetos
Exemplo: pattern strategy para operador binário com o símbolo
como parâmetro sem usar “classes”
–
Baseado em (o link possui uma versão em C e várias em Python):
https://github.com/danilobellini/design_patterns
def
def add(x,
add(x, y):
y): return
return xx ++ yy
def
def sub(x,
sub(x, y):
y): return
return xx -- yy
def
def mod(x,
mod(x, y):
y): return
return xx %% yy
ops
ops == {{
"+":
"+": add,
add,
"-":
sub,
"-": sub,
"%":
"%": mod,
mod,
}}
Alte
rnat
ivas
def
def apply_op(symbol,
apply_op(symbol, x,
x, y):
y):
return
ops[symbol](x,
return ops[symbol](x, y)
y)
ops
ops == {{
"+":
"+": lambda
lambda x,
x, y:
y: xx ++ y,
y,
"-":
"-": lambda
lambda x,
x, y:
y: xx -- y,
y,
"%":
lambda
x,
y:
x
%
y,
"%": lambda x, y: x % y,
}}
template
template == "lambda
"lambda x,
x, y:
y: xx %s
%s y"
y"
ops
=
{s:
eval(template
%
s)
for
ops = {s: eval(template % s) for ss in
in "+-*/%"}
"+-*/%"}
print(apply_op("+",
print(apply_op("+", 2,
2, 3))
3)) ## 55
print(apply_op("-",
7))
print(apply_op("-",
5,
7)) ## -2
-2
Danilo J. S. Bellini –5,
@danilobellini
– Tutorial: Adaptatividade em Python
print(apply_op("%",
22,
13))
#
9
print(apply_op("%",
22, 13)) –#São
9 Paulo – SP – 2015-01-29 e 2015-01-30
Workshop de Tecnologia Adaptativa
[Lexical] Closure
●
“Função” + “contexto”
Blocos “instanciáveis” (e.g. funções anônimas)
+ (com)
“Variáveis livres” (definidas para cada “instância”)
●
Caso típico: aplicação parcial
def
def adder(a):
adder(a):
return
return lambda
lambda b:
b: bb ++ aa
add2
add2 == adder(2)
adder(2)
sub1
=
adder(-1)
sub1 = adder(-1)
print(add2(15))
## 17
print(add2(15))
17
print(sub1(4))
## 33
print(sub1(4))
print(add2(sub1(8)))
print(add2(sub1(8))) ## 99
“b” é o único parâmetro da
função anônima devolvida,
“a” é uma variável livre
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Quantidades e nomes de
parâmetros em funções/métodos
●
def/lambda
–
●
●
Posicionais
–
●
2. (1x) * unário, continuação dos
argumentos posicionais com qualquer
iterável
Pertencem à
função/método
Mutabilidade → influencia
em todas as chamadas
Argumentos extras
* unário → tupla
Nominados (keyword)
–
** unário → dicionário
Chamada (todo item é opcional)
1. Argumentos posicionais
Valores default com “=”
●
–
●
3. Pares “chave=valor” explícitos
4. (1x) ** unário, utiliza todos os pares
“chave=valor” de um dicionário
●
* e ** unários da chamada não são
os mesmos recebidos pela função
como argumentos
–
Verificação dos nomes, quantidades,
excessos, ausências e repetições
(TypeError)
def
def smaller_first(pair):
smaller_first(pair):
k,
k, vv == pair
pair
return
len(k),
return len(k), kk
def
def show_it_all(a,
show_it_all(a, b,
b, c=None,
c=None, *args,
*args, **kwargs):
**kwargs):
for
k,
v
in
sorted(locals().items(),
Danilo J. S. for
Bellinik,
– @danilobellini
– Tutorial: Adaptatividade key=smaller_first):
em
Python
v in sorted(locals().items(),
key=smaller_first):
print("{:>6}:
{}".format(k,
v))
Workshop de Tecnologia
Adaptativa – São
Paulo – SP – 2015-01-29
e 2015-01-30
print("{:>6}:
{}".format(k,
v))
squares
squares == [i
[i **
** 22 for
for ii in
in range(10)]
range(10)]
ascii
=
{ch:
hex(ord(ch))
for
ascii = {ch: hex(ord(ch)) for ch
ch in
in "Place"}
"Place"}
>>>
>>>show_it_all(0,
show_it_all(0,-1)
-1)
a:
0
a: 0
b:
b:-1
-1
c:
c: None
None
args:
()
args: ()
kwargs:
kwargs: {}
{}
>>>
>>>show_it_all(*"First")
show_it_all(*"First")
a:
a: FF
b:
b: ii
c:
c: rr
args:
args:('s',
('s','t')
't')
kwargs:
{}
kwargs: {}
>>>
>>>show_it_all(b=0,
show_it_all(b=0,a=-1)
a=-1)
a:
-1
a: -1
b:
b:00
c:
c: None
None
args:
()
args: ()
kwargs:
kwargs: {}
{}
>>>
>>>show_it_all(*squares)
show_it_all(*squares)
a:
0
a: 0
b:
b:11
c:
c:44
args:
args:(9,
(9,16,
16,25,
25,36,
36,49,
49,64,
64,81)
81)
kwargs:
{}
kwargs: {}
>>>
>>>show_it_all(1,
show_it_all(1,2,
2,3,
3,4,
4,5,
5,d=415)
d=415)
a:
1
a: 1
b:
>>>
b:22
>>>show_it_all(-5,
show_it_all(-5,*squares,
*squares,args=415)
args=415)
c:
3
a:
-5
c: 3
a: -5
args:
(4,
5)
b:
args: (4, 5)
b:00
kwargs:
c:
kwargs:{'d':
{'d':415}
415}
c:11
args:
args:(4,
(4,9,
9,16,
16,25,
25,36,
36,49,
49,64,
64,81)
81)
kwargs:
{'args':
415}
>>>
show_it_all(b="Second",
**ascii)
kwargs: {'args': 415}
>>> show_it_all(b="Second", **ascii)
a:
a:0x61
0x61
b:
## TypeError
b: Second
Second
TypeError
show_it_all("First",
c:
0x63
show_it_all("First", **ascii)
**ascii) ## "a"
"a" 2x
2x
c: 0x63
args:
()
show_it_all(*squares,
**ascii)
#
"a"
2x
args: ()
show_it_all(*squares, **ascii) # "a" 2x
show_it_all(1,
kwargs:
{'P':
'0x50',
'e':
'0x65',
'l':
'0x6c'}
show_it_all(1, 2,
2, 3,
3, 4,
4, 5,
5, b=5)
b=5) ## "b"
"b" 2x
2x
kwargs: {'P': '0x50', 'e': '0x65', 'l': '0x6c'}
show_it_all(b=5,
e=0,
**ascii)
#
"e"
2x
show_it_all(b=5, e=0, **ascii) # "e" 2x
show_it_all(**ascii)
show_it_all(**ascii) ## "b"
"b" ausente
ausente
def
smaller_first(pair):
def smaller_first(pair):
show_it_all(0)
#
"b"
ausente
show_it_all(0)
# "b" ausente
k,
k, vv == pair
pair
show_it_all()
#
show_it_all()
# "a"
"a" ausente
ausente
return
len(k),
k
return len(k), k
def
def show_it_all(a,
show_it_all(a, b,
b, c=None,
c=None, *args,
*args, **kwargs):
**kwargs):
for
k,
v
in
sorted(locals().items(),
key=smaller_first):
for
k, J.vS.in
sorted(locals().items(),
key=smaller_first):
Danilo
Bellini
–
@danilobellini
–
Tutorial:
Adaptatividade
em Python
Quanta coisa...
print("{:>6}:
{}".format(k,
v))
print("{:>6}:
{}".format(k,
v))
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Decorator
## coding:
coding: utf-8
utf-8
from
functools
from functools import
import wraps,
wraps, reduce
reduce
●
def
def double_of(func):
double_of(func):
●
"""Decorator
que
dobra
o
resultado
da
função."""
"""Decorator que dobra o resultado da função."""
@wraps(func)
@wraps(func) ## Copia
Copia informações
informações de
de func
func
def
wrapper(*args,
**kwargs):
def wrapper(*args, **kwargs):
return
return 22 ** func(*args,
func(*args, **kwargs)
**kwargs)
return
wrapper
return wrapper
sum_twice
sum_twice == double_of(sum)
double_of(sum)
print(sum_twice([2,
print(sum_twice([2, 5,
5, 3]))
3])) ## 20
20
@double_of
@double_of
def
def prod_twice(data):
prod_twice(data):
return
return reduce(lambda
reduce(lambda x,
x, y:
y: xx ** y,
y, data,
data, 1)
1)
print(prod_twice([2,
print(prod_twice([2, 5,
5, 3]))
3])) ## 60
60
●
Função
1 parâmetro
–
1 valor de saída
–
●
Função ou
classe
Normalmente
função ou classe
Uso com o @
Usa o nome do
próprio objeto
“decorado”
–
## AA menos
menos dos
dos nomes,
nomes, oo acima
acima éé oo mesmo
mesmo que:
que:
def
def prod(data):
prod(data):
return
return reduce(lambda
reduce(lambda x,
x, y:
y: xx ** y,
y, data,
data, 1)
1)
prod2x
=
double_of(prod)
#
Decorator!
prod2x = double_of(prod) # Decorator!
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
print(prod2x([2,
5,
print(prod2x([2,
5, 3]))
3])) ## 60
60
Workshop de Tecnologia
Adaptativa
– São Paulo – SP – 2015-01-29 e 2015-01-30
Métodos com “self” explícito?
●
Currying!
–
Aplicação parcial do
primeiro parâmetro
class
class MsgKeeper(object):
MsgKeeper(object):
def
def __init__(self,
__init__(self, msg):
msg):
self.msg
=
msg
self.msg = msg
def
def show(self):
show(self):
print(self.msg)
print(self.msg)
foo
foo == MsgKeeper("foo")
MsgKeeper("foo")
bar
=
MsgKeeper("bar")
bar = MsgKeeper("bar")
foo.show()
foo.show()
bar.show()
bar.show()
MsgKeeper.show(foo)
MsgKeeper.show(foo)
MsgKeeper.show(bar)
MsgKeeper.show(bar)
●
Aninhamento
–
●
“self” é um nome arbitrário
Classes de primeira
classe (+ closure)
–
Exemplos:
●
audiolazy.StrategyDict
–
●
Docstring dinâmica e por
instância
dose (tratamento de
eventos do watchdog)
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
class
class MsgKeeper(object):
MsgKeeper(object):
def
def __init__(self,
__init__(self, msg):
msg):
self.msg
self.msg == msg
msg
def
show(self):
def show(self):
print(self.msg)
print(self.msg)
## Definido
Definido fora
fora do
do namespace
namespace da
da classe
classe
def
prefixed_keeper(self):
def prefixed_keeper(self):
class
class PrefixedKeeper(MsgKeeper):
PrefixedKeeper(MsgKeeper):
@property
@property
def
def msg(this):
msg(this):
return
return self.msg
self.msg ++ this._msg
this._msg
@msg.setter
@msg.setter
def
def msg(this,
msg(this, value):
value):
this._msg
this._msg == value
value
return
return PrefixedKeeper
PrefixedKeeper
turn
turn == MsgKeeper("turn")
MsgKeeper("turn")
O método prefixed_keeper
não existia quando turn foi
instanciado!
Classe de
primeira classe
e Monkeypatch
Monkeypatch:
atualização da
classe em
tempo de
execução
## Monkeypatch
Monkeypatch
MsgKeeper.prefixed_keeper
MsgKeeper.prefixed_keeper == prefixed_keeper
prefixed_keeper
## (poderia
(poderia ser
ser definido
definido dentro
dentro da
da classe)
classe)
turno
turno == turn.prefixed_keeper()("o")
turn.prefixed_keeper()("o")
turnon
=
turnon = turno.prefixed_keeper()("n")
turno.prefixed_keeper()("n")
turn.show()
turn.show() ## turn
turn
turno.show()
#
turno
turno.show() # turno
turnon.show()
turnon.show() ## turnon
turnon
turn.msg
=
"Pyth"
turn.msg = "Pyth"
turnon.show()
turnon.show() ## Python
Python
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Parte 3
Namespaces,
dicionários e
escopo (léxico)
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Dicionário da classe e
dicionário da instância
●
●
●
Tudo em Python é um objeto
Namespaces são representados
como dicionários
Objetos e classes [normalmente]
possuem um namespace de atributos
–
“vars(obj)”
●
●
Dicionário (__dict__)
Nem sempre é aplicável
–
–
Tipos built-ins, __slots__
“dir(obj)”
●
●
class
class A(object):
A(object):
data
data == "Testing"
"Testing"
def
__init__(self,
def __init__(self, data):
data):
self.data
=
data
self.data = data
other
other == A("Other")
A("Other")
## Digitar
Digitar no
no IPython:
IPython:
A.data
A.data
other.data
other.data
type(other)
type(other) ## other.__class__
other.__class__
type(other).data
type(other).data
vars(other)
vars(other)
vars(A)
vars(A)
## EE se
se apagarmos
apagarmos da
da instância?
instância?
del
other.data
del other.data
vars(other)
vars(other)
other.data
other.data
__slots__ = [“__dict_
_”]
Lista de nomes (strings) dos atributos,
incluindo os da classe/herança (exceto os
da metaclasse)
Sempre aplicável
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
In
In [1]:
[1]: class
class A(object):
A(object):
...:
data
...:
data == "Testing"
"Testing"
...:
def
__init__(self,
...:
def __init__(self, data):
data):
...:
self.data
=
data
...:
self.data = data
...:
...:
In
In [2]:
[2]: other
other == A("Other")
A("Other")
In
In [3]:
[3]: A.data
A.data
Out[3]:
'Testing'
Out[3]: 'Testing'
In
In [4]:
[4]: other.data
other.data
Out[4]:
'Other'
Out[4]: 'Other'
In
In [5]:
[5]: type(other)
type(other)
Out[5]:
__main__.A
Out[5]: __main__.A
In
In [6]:
[6]: type(other).data
type(other).data
Out[6]:
'Testing'
Out[6]: 'Testing'
In
In [7]:
[7]: vars(other)
vars(other)
Out[7]:
{'data':
Out[7]: {'data': 'Other'}
'Other'}
Resolução
dinâmica de
atributos
In
In [9]:
[9]: del
del other.data
other.data
Atributos do objeto
(exceto para
dunders)
In
In [10]:
[10]: vars(other)
vars(other)
Out[10]:
Out[10]: {}
{}
In
In [11]:
[11]: other.data
other.data
Out[11]:
'Testing'
Out[11]: 'Testing'
Atributos
da classe
Herança (MRO)
In
In [8]:
[8]: vars(A)
vars(A)
Out[8]:
Out[8]:
<dictproxy
<dictproxy {'__dict__':
{'__dict__': <attribute
<attribute '__dict__'
'__dict__' of
of 'A'
'A' objects>,
objects>,
'__doc__':
None,
'__doc__': None,
'__init__':
'__init__': <function
<function __main__.__init__>,
__main__.__init__>,
'__module__':
'__main__',
'__module__': '__main__',
'__weakref__':
'__weakref__': <attribute
<attribute '__weakref__'
'__weakref__' of
of 'A'
'A' objects>,
objects>,
'data':
'Testing'}>
Danilo'Testing'}>
J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
'data':
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
?
Docstrings, help
●
Strings são imutáveis
●
Primeira string (literal) do bloco
–
Módulo
–
Classe
–
Método/Função
●
Built-in “help()”
●
Dunder __doc__
–
Referência fixa em classes
●
–
●
Dinâmico se __doc__ for uma
property (e.g. audiolazy.StrategyDict)
Referência modificável em
módulos e métodos/funções (uso
intenso na AudioLazy)
Documentação no próprio
código
Dicas
Dicas para
para uso
uso do
do IPython
IPython
TAB
->
TAB
-> Code
Code completion
completion
?? ao
final
->
Docstring
ao final -> Docstring ++ extras
extras
??
ao
final
->
Código-fonte
?? ao final -> Código-fonte
## coding:
coding: utf-8
utf-8
def
is_palindrome(val):
def is_palindrome(val):
"""
"""
Verifica
Verifica se
se aa representação
representação do
do valor
valor
fornecido
é
um
palíndromo
fornecido é um palíndromo
"""
"""
as_string
as_string == repr(val)
repr(val)
return
as_string
return as_string ==
== as_string[::-1]
as_string[::-1]
## Rodar
Rodar em
em um
um REPL
REPL
is_palindrome(123213)
is_palindrome(123213) ## False
False
is_palindrome(123321)
#
True
is_palindrome(123321) # True
help(is_palindrome)
help(is_palindrome) ## Exibe
Exibe aa docstring
docstring ee
## outras
outras informações
informações
is_palindrome.__doc__
is_palindrome.__doc__ ## Devolve
Devolve aa docstring
docstring
#\n
#\n
#----Verifica
#----Verifica se
se aa representação
representação do
do valor\n
valor\n
#----fornecido
é
um
palíndromo\n
#----fornecido é um palíndromo\n
#---#----
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Locals & globals
●
●
locals
2 namespaces por contexto (escopo
léxico): “local” e “global”
globals
Funções built-in
built-ins
–
locals()
–
globals()
–
dir()
●
●
Resolução
de nomes:
Sem parâmetro fornece os nomes (chaves) de
“locals()”
Modificar o resultado de “locals()”
apenas possui o efeito de mudança do
namespace no nível do módulo/script
(ou direto no REPL)
from
from math
math import
import factorial
factorial
for
for ii in
in range(35):
range(35):
locals()["f%d"
locals()["f%d" %% i]
i] == factorial(i)
factorial(i)
print(f0)
print(f0) ## 11
print(f1)
print(f1) ## 11
print(f5)
print(f5) ## 120
120
print(f15)
#
print(f15) # 1307674368000
1307674368000
print(dir())
print(dir()) ## Como
Como script,
script, Python
Python 2:
2:
#['__builtins__',
'__doc__',
– Manipulação do namespace a partir de
#['__builtins__', '__doc__',
#
strings e valores ao invés de nomes em
# '__file__',
'__file__', '__name__',
'__name__',
#
'__package__',
código
# '__package__', 'f0',
'f0', 'f1',
'f1', 'f10',
'f10',
## 'f11',
'f11', 'f12',
'f12', 'f13',
'f13', 'f14',
'f14', 'f15',
'f15',
Módulos audiolazy.lazy_math e
#
'f16',
'f17',
'f18',
'f19',
'f2',
audiolazy.lazy_itertools
# 'f16', 'f17', 'f18', 'f19', 'f2',
## 'f20',
'f20', 'f21',
'f21', 'f22',
'f22', 'f23',
'f23', 'f24',
'f24',
– Criação massiva / automação
## 'f25',
'f26',
'f27',
'f28',
'f29',
'f25', 'f26', 'f27', 'f28', 'f29',
– Uso de dados ao invés de estrutura
## 'f3',
'f3', 'f30',
'f30', 'f31',
'f31', 'f32',
'f32', 'f33',
'f33',
#
'f34',
'f4',
'f5',
'f6',
'f7',
# 'f34', 'f4',
'f5', 'f6', 'f7',
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade
em Python
#
'f8',
'f9',
'factorial',
'f9',
'factorial', 'i']
'i']
Workshop de Tecnologia Adaptativa – São Paulo – SP#– 'f8',
2015-01-29
e 2015-01-30
●
“Escopo dinâmico”?
## coding:
coding: utf-8
utf-8
template
=
template = u"{level}
u"{level} ({author}):
({author}): {msg}"
{msg}"
print(template.format(
print(template.format(
msg
msg == u"Isto
u"Isto não
não éé uma
uma mensagem.",
mensagem.",
level
=
u"Info",
level = u"Info",
author
author == u"Danilo",
u"Danilo",
))
#
Exibe:
)) # Exibe:
## Info
Info (Danilo):
(Danilo): Isto
Isto não
não éé uma
uma mensagem.
mensagem.
msg
msg == u"Contexto
u"Contexto como
como parâmetro?"
parâmetro?"
level
=
u"Dinâmico"
level = u"Dinâmico"
author
author == u"Locals!"
u"Locals!"
print(template.format(**locals()))
print(template.format(**locals())) ## Exibe:
Exibe:
## Dinâmico
(Locals!):
Contexto
como
parâmetro?
Dinâmico (Locals!): Contexto como parâmetro?
●
É possível a passagem do resultado de locals() como parâmetro
–
No exemplo, recebe como “**kwargs”, não como valores despejados no
locals() externo.
–
Valores mutáveis (e.g. listas) podem ser modificados.
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Documentação automática
●
●
audiolazy.StrategyDict
–
Dicionário de estratégias
–
Múltiplas implementações de “coisas
similares”
–
Iterável pelas estratégias
–
Mutável
–
Callable (estratégia default)
–
Estratégias acessíveis como atributos e
como itens
–
Docstring dinâmica (resumo das
docstrings das estratégias)
audiolazy.format_docstring
–
Decorator p/ fazer docstrings com a
partir de template
●
Sphinx (reflexão)
–
Geração de documentação
em HTML, LaTeX, PDF,
man pages, etc.
–
conf.py + reStructuredText
+ docstrings (em
reStructuredText)
–
Equacionamentos
matemáticos em LaTeX
–
Integração com Matplotlib
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
audiolazy.format_docstring
## coding:
coding: utf-8
utf-8
## Código
original
Código original na
na AudioLazy
AudioLazy (exceto
(exceto pela
pela docstring):
docstring):
def
def format_docstring(template_="{__doc__}",
format_docstring(template_="{__doc__}", *args,
*args, **kwargs):
**kwargs):
def
decorator(func):
def decorator(func):
if
if func.__doc__:
func.__doc__:
kwargs["__doc__"]
kwargs["__doc__"] == func.__doc__.format(*args,
func.__doc__.format(*args, **kwargs)
**kwargs)
func.__doc__
=
template_.format(*args,
**kwargs)
func.__doc__ = template_.format(*args, **kwargs)
return
return func
func
return
decorator
return decorator
## Exemplo
Exemplo
def
def adder(a):
adder(a):
@format_docstring(a=a)
@format_docstring(a=a)
def
def add(b):
add(b):
"""Efetua
"""Efetua aa soma
soma {a}
{a} ++ bb para
para oo dado
dado b."""
b."""
return
a
+
b
return a + b
return
return add
add
add3
add3 == adder(3)
adder(3)
sub2
=
adder(-2)
sub2 = adder(-2)
help(add3)
help(add3) ## Efetua
Efetua aa soma
soma 33 ++ bb para
para oo dado
dado b.
b.
help(sub2)
help(sub2) ## Efetua
Efetua aa soma
soma -2
-2 ++ bb para
para oo dado
dado b.
b.
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Parte 4
Fallback e reflexão
(reflection) para
itens e atributos
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Dunder
__missing__
●
●
“Fallback” para
tentativa de
acessar item
inexistente no
dicionário
Necessita de
uma nova
classe
(herança)
## coding:
coding: utf-8
utf-8
from
__future__
from __future__ import
import unicode_literals
unicode_literals
## Vamos
remover
acentos!
Vamos remover acentos!
class
class DictDefaultsToKey(dict):
DictDefaultsToKey(dict):
def
def __missing__(self,
__missing__(self, key):
key):
return
key
return key
rev_ascii
rev_ascii == {{
"a":
"a": "áàãâāäă",
"áàãâāäă", "A":
"A": "ÁÀÃÂĀÄĂ",
"ÁÀÃÂĀÄĂ",
"e":
"éè
ẽ
êēëĕ"
,
"E":
"ÉÈ
"e": "éèẽêēëĕ", "E": "ÉÈẼẼÊĒËĔ"
ÊĒËĔ",,
"i":
"i": "íìĩîīïĭ
"íìĩîīïĭ",
", "I":
"I": "ÍÌĨÎĪÏĬ",
"ÍÌĨÎĪÏĬ",
"o":
"óòõôōöŏ",
"O":
"ÓÒÕÔŌÖŎ",
"o": "óòõôōöŏ", "O": "ÓÒÕÔŌÖŎ",
"u":
"u": "úùũûūüŭ",
"úùũûūüŭ", "U":
"U": "ÚÙŨÛŪÜŬ",
"ÚÙŨÛŪÜŬ",
"c":
"C":
"c": "ç",
"ç",
"C": "Ç",
"Ç",
"n":
"ñ",
"N":
"Ñ",
"n": "ñ",
"N": "Ñ",
}}
ascii_dict
ascii_dict == DictDefaultsToKey()
DictDefaultsToKey()
for
k,
values
for k, values in
in rev_ascii.items():
rev_ascii.items():
ascii_dict.update((v,
ascii_dict.update((v, k)
k) for
for vv in
in values)
values)
def
def to_ascii(msg):
to_ascii(msg):
return
return "".join(ascii_dict[ch]
"".join(ascii_dict[ch] for
for ch
ch in
in msg)
msg)
## Exemplos
Exemplos
to_ascii("La
to_ascii("La cédille:
cédille: ç/Ç
ç/Ç (Forçação
(Forçação de
de barra)")
barra)")
to_ascii("Qui
a
décidé
d'être
naïf?")
to_ascii("Qui a décidé d'être naïf?")
to_ascii("ñÑãÃsáÁüúù...")
to_ascii("ñÑãÃsáÁüúù...")
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
__getitem__, __call__
## -*-*- coding:
coding: utf-8
utf-8 -*-*from
functools
import
from functools import reduce
reduce
from
from operator
operator import
import add,
add, mul
mul
●
class
class SumProd(object):
SumProd(object):
def
def __init__(self):
__init__(self):
self.count
self.count == 00
def
def __getitem__(self,
__getitem__(self, key):
key): ## 11 argumento!
argumento!
"""Somatório
(não-vazio)"""
"""Somatório (não-vazio)"""
self.count
self.count +=
+= 11
return
return reduce(add,
reduce(add, key)
key)
def
def __call__(self,
__call__(self, *key):
*key):
"""Produtório
(não-vazio)"""
"""Produtório (não-vazio)"""
self.count
self.count +=
+= 11
return
return reduce(mul,
reduce(mul, key)
key)
sp
sp == SumProd()
SumProd()
print(
->
print( sp(3,
sp(3, 4,
4, 5)
5) )) ## __call__
__call__
-> 60
60
print(
sp[3,
4,
5]
)
#
__getitem__
->
12
print( sp[3, 4, 5] ) # __getitem__ -> 12
print(sp.count)
print(sp.count)##22
●
__getitem__
–
“Operador” []
–
1 único parâmetro
(chave), que pode
ser uma tupla
__call__
–
“Operador” ()
–
Permite tratar
objetos quaisquer
como funções
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Dunders get/set/delete para itens e
atributos do objeto
●
●
●
Item
https://docs.python.org/3/reference/datamodel.html
–
__getitem__ : obj[key]
–
__setitem__ : obj[key] = value
–
__delitem__ : del obj[key]
Atributo
–
__setattr__ : obj.key = value
–
__delattr__ : del obj.key
Leitura de atributo
–
__getattr__ : obj.key
●
–
Chamado quando “key not in dir(obj)”
__getattribute__ : obj.key
●
●
Conteúdo que TODO
pythonista deveria
conhecer!
Inclui os dunders dos
operadores, de descriptors,
chamadas por built-ins,
context managers, etc.
[Quase] incondicional
Não é chamado se o “key” for um dunder chamado internamente por um built-in
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
## coding:
coding: utf-8
utf-8
from
random
from random import
import choice,
choice, randint
randint
from
string
import
ascii_lowercase
from string import ascii_lowercase
def
def mastermind(guess,
mastermind(guess, secret):
secret):
"""
"""
Compara
Compara as
as strings
strings de
de entrada
entrada ee devolve
devolve um
um par
par de
de inteiros
inteiros
(caracteres
corretos
na
posição
correta,
(caracteres corretos na posição correta,
caracteres
caracteres corretos
corretos se
se desconsiderarmos
desconsiderarmos aa posição)
posição)
Origem:
Origem: https://gist.github.com/danilobellini/5311427
https://gist.github.com/danilobellini/5311427
"""
"""
return
return sum(1
sum(1 for
for g,
g, ss in
in zip(guess,
zip(guess, secret)
secret) if
if gg ==
== s),
s), \\
sum(min(guess.count(x),
sum(min(guess.count(x), secret.count(x))
secret.count(x)) for
for xx in
in set(secret))
set(secret))
class
class NameMastermind(object):
NameMastermind(object):
def
def __init__(self):
__init__(self):
size
size == randint(3,
randint(3, 8)
8)
name
=
"".join(choice(ascii_lowercase)
name = "".join(choice(ascii_lowercase) for
for el
el in
in xrange(size))
xrange(size))
self._name
=
name
self._name = name
setattr(self,
setattr(self, name,
name, lambda:
lambda: "Yeah!")
"Yeah!")
def
__getattr__(self,
name):
def __getattr__(self, name):
return
return lambda:
lambda: mastermind(name,
mastermind(name, self._name)
self._name)
game
#game.lmpq()
game == NameMastermind()
NameMastermind()
#game.lmpq() ## ->
-> (0,
(0, 1)
1)
## Para
rodar
no
REPL...
#game.lmgq()
#
->
(0,
2)
Para rodar no REPL...
#game.lmgq() # -> (0, 2)
## NÃO
APERTE
TAB!
Exemplo:
#game.lmqg()
NÃO APERTE TAB! Exemplo:
#game.lmqg() ## ->
-> (0,
(0, 2)
2)
#game.abcd()
#
->
(0,
0)
#game.rstu()
#
->
(0,
0)
#game.abcd() # -> (0, 0)
#game.rstu() # -> (0, 0)
#game.efgh()
#
->
(1,
2)
#game.vwxy()
#game.efgh() # -> (1, 2)
#game.vwxy() ## ->
-> (0,
(0, 1)
1)
#game.eeff()
#
->
(0,
0)
#game.lgzh()
#
->
(1,
3)
#game.eeff() # -> (0, 0)
#game.lgzh() # -> (1, 3)
#game.ijkh()
#
->
(1,
1)
#game.gmvh()
## ->
#game.ijkh()
# -> (1, 1)
#game.gmvh()
-> (2,
(2, 2)
2)
Danilo
J.
S.
Bellini
–
@danilobellini
–
Tutorial:
Adaptatividade
em
Python
#game.lmno()
#
->
(0,
1)
#game.glwh()
#
->
'Yeah!'
# -> (0,
1) Paulo – SP –#game.glwh()
# -> 'Yeah!'
Workshop#game.lmno()
de Tecnologia Adaptativa
– São
2015-01-29 e 2015-01-30
Funções built-in
hasattr, getattr, setattr
●
hasattr
–
Devolve um booleano
indicando se o atributo existe
–
Pode chamar __getattr__
●
●
E se __getattr__ tiver efeito
colateral?
getattr e setattr
–
Particularmente útil para
acessar atributos por strings
dos nomes ou iterar em
módulos
●
Módulos também são
objetos!
–
Pode-se usar hasattr,
getattr, setattr
import
import itertools
itertools
if
hasattr(itertools,
if hasattr(itertools, "accumulate"):
"accumulate"):
print("Python
3")
#
print("Python 3") # AA rigor,
rigor, 3.2+
3.2+
else:
else:
print("Python
print("Python 2")
2") ## Talvez
Talvez 3.0
3.0 // 3.1
3.1
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Parte 5
MRO, herança
múltipla, __new__,
metaclasses
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
MRO
Method Resolution Order
●
Python tem herança múltipla
–
Linearizarização C3
●
Grafo de herança → MRO
class
class A(object):
A(object): pass
pass
class
B(A):
pass
class B(A): pass
class
class C(A):
C(A): pass
pass
class
D(B,
C):
class D(B, C): pass
pass
classes
classes == [A,
[A, B,
B, C,
C, D]
D]
instances
=
[cls()
for
instances = [cls() for cls
cls in
in classes]
classes]
def
def msg_returner(msg):
msg_returner(msg):
return
return lambda
lambda self:
self: msg
msg
show_all()
show_all() ## AA BB CC DD
del
del C.__str__
C.__str__
show_all()
show_all() ## AA BB AA DD
C.__str__
C.__str__ == msg_returner("3")
msg_returner("3")
show_all()
#
show_all() # AA BB 33 DD
del
del D.__str__
D.__str__
show_all()
show_all() ## AA BB 33 BB
del
del B.__str__
B.__str__
show_all()
show_all() ## AA AA 33 33
del
del C.__str__
C.__str__
show_all()
show_all() ## AA AA AA AA
print(D.mro())
print(D.mro())
## [<class
[<class '__main__.D'>,
'__main__.D'>,
## <class
'__main__.B'>,
<class '__main__.B'>,
#
<class
def
# <class '__main__.C'>,
'__main__.C'>,
def show_all():
show_all():
#
<class
'__main__.A'>,
print("{}
{}
{}
{}".format(*instances))
# <class
'__main__.A'>,
print("{}
{} –{}".format(*instances))
Danilo J. S. {}
Bellini
@danilobellini – Tutorial: Adaptatividade
em Python
## <type
'object'>]
<type
'object'>]
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29
e 2015-01-30
for
for cls
cls in
in classes:
classes:
cls.__str__
cls.__str__ == msg_returner(cls.__name__)
msg_returner(cls.__name__)
!
A
B
D
C
type, isinstance, issubclass
●
type(name, bases, namespace)
–
Devolve tipos/classes
AA == type("A",
type("A", (object,),
(object,), {"__str__":
{"__str__": lambda
lambda self:
self: "A"})
"A"})
BB == type("B",
(A,),
{"__str__":
lambda
self:
"B"})
type("B", (A,),
{"__str__": lambda self: "B"})
CC == type("C",
(A,),
{"__str__":
type("C", (A,),
{"__str__": lambda
lambda self:
self: "C"})
"C"})
DD == type("D",
(B,
C),
{"__str__":
lambda
self:
"D"})
type("D", (B, C),
{"__str__": lambda self: "D"})
## Já
com
os
métodos
__str__
Já com os métodos __str__ no
no namespace!
namespace! [...]
[...]
●
isinstance(obj, cls)
–
cls in type(obj).mro()
–
cls pode ser uma tupla
●
●
Lembrando que o 1o
elemento da MRO é
a própria classe
any(c in type(obj).mro() for c in cls)
issubclass(cls1, cls2)
–
cls2 in cls1.mro()
–
cls2 pode ser uma tupla
any(c in cls1.mro() for c in cls2)
a,
a, b,
b, c,
c, dd == A(),
A(), B(),
B(), C(),
C(), D()
D()
print(isinstance(d,
## True
print(isinstance(d, A))
A))
True
print(isinstance(a,
(B,
C)))
#
False
print(isinstance(a, (B, C))) # False
print(isinstance(c,
print(isinstance(c, (B,
(B, C)))
C))) ## True
True
print(issubclass(A,
## False
print(issubclass(A, B))
B))
False
print(issubclass(B,
A))
#
True
print(issubclass(B,
A))
# True
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade
em Python
print(issubclass(B,
(C,
D)))
#
False
print(issubclass(B,
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29
e 2015-01-30 (C, D))) # False
●
super(MsgKeeper, cls) é
class
class MsgKeeper(object):
MsgKeeper(object):
[um proxy de] object
def
def __new__(cls,
__new__(cls, msg):
msg):
instance
instance == super(MsgKeeper,
super(MsgKeeper, cls).__new__(cls)
cls).__new__(cls)
instance.msg
=
msg
instance.msg = msg
return
return instance
instance if
if msg
msg !=
!= "Certa!"
"Certa!" else
else -1
-1
@classmethod
@classmethod
def
def alt_new(cls,
alt_new(cls, msg):
msg):
return
cls(msg[::-1])
return cls(msg[::-1])
Construtor
__new__
e
decorator
@classmethod
obj
obj == MsgKeeper("Minha
MsgKeeper("Minha mensagem!")
mensagem!")
print(obj)
#
<__main__.MsgKeeper
print(obj)
# <__main__.MsgKeeper object
object at
at 0x...>
0x...>
print(obj.msg)
#
Minha
mensagem!
print(obj.msg) # Minha mensagem!
print(MsgKeeper("Certa!"))
print(MsgKeeper("Certa!")) ## -1
-1
obj_alt
obj_alt == MsgKeeper.alt_new("Certa!")
MsgKeeper.alt_new("Certa!")
print(obj_alt.msg)
print(obj_alt.msg) ## !atreC
!atreC
●
●
Primeiro elemento é a classe, não a instância “self”
–
__new__(cls, …)
–
O mesmo efeito pode ser obtido com o decorator
@classmethod
Precisa devolver a instância
–
Que sequer precisa ter a ver com “cls”...
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Metaclasses
●
A classe da classe
–
Normalmente “type” é a classe de todas as classes
●
–
●
Usar novos nomes pode ajudar: “cls” e “mcls” no lugar de “self” é “cls”
Duas sintaxes
–
Python 2
●
–
–
__metaclass__ no namespace
Python 3
●
argumento nominado “metaclass=” após as bases da herança
Problema sério para compatibilidade em código único
●
●
●
“type” está para as metaclasses assim como “object” está para as classes
six → Cria um nível de herança “dummy” para manter sintaxe única
AudioLazy → Função “meta” no lugar das bases da herança permite usar a sintaxe
similar à do Python 3 compatível com ambos
Classes criadas por herança TAMBÉM compartilham a metaclasse
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Metaclasse que apenas avisa
quando instancia a classe
import
import sys
sys
class
class Metaclass(type):
Metaclass(type):
def
def __init__(cls,
__init__(cls, name,
name, bases,
bases, namespace):
namespace):
print("Initializing
class
{}\n"
print("Initializing class {}\n"
"bases:
"bases: {}\n"
{}\n"
"namespace:
"namespace: {}"
{}"
.format(name,
.format(name, bases,
bases, namespace))
namespace))
if
if sys.version_info.major
sys.version_info.major ==
== 2:
2: ## Python
Python 22
exec("""class
exec("""class M1(object):
M1(object): __metaclass__
__metaclass__ == Metaclass""")
Metaclass""")
else:
#
Python
3
else: # Python 3
exec("""class
exec("""class M1(object,
M1(object, metaclass=Metaclass):
metaclass=Metaclass): pass""")
pass""")
## Initializing
Initializing class
class M1
M1
## bases:
(<class
'object'>,)
bases: (<class 'object'>,)
## namespace:
namespace: {'__module__':
{'__module__': '__main__',
'__main__', …}
…}
## Similar:
Similar: M1
M1 == Metaclass("M1",
Metaclass("M1", (object,),
(object,), {})
{})
## (mas
o
namespace
resultante
nem
'__module__'
(mas o namespace resultante nem '__module__' possui)
possui)
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
class
class PairMetaClass(AbstractOperatorOverloaderMeta):
PairMetaClass(AbstractOperatorOverloaderMeta):
__without__
__without__ == "r"
"r" ## Sem
Sem ops
ops reversos
reversos __rbinary__
__rbinary__
def
def __binary__(cls,
__binary__(cls, opmeth):
opmeth):
return
lambda
self,
return lambda self, other:
other: \\
cls(opmeth.func(self.x,
cls(opmeth.func(self.x, other.x),
other.x),
opmeth.func(self.y,
other.y))
opmeth.func(self.y, other.y))
def
def __unary__(cls,
__unary__(cls, opmeth):
opmeth):
return
lambda
self:
return lambda self: \\
cls(opmeth.func(self.x),
cls(opmeth.func(self.x),
opmeth.func(self.y))
opmeth.func(self.y))
## Exemplo
Exemplo de
de vars(opmeth):
vars(opmeth):
{'arity':
{'arity': 2,
2,
'symbol':
'symbol': '+',
'+',
'func':
<function
'func': <function
_operator.add>,
_operator.add>,
'name':
'add',
'name': 'add',
'dname':
'dname': '__add__',
'__add__',
'rev':
False}
'rev': False}
class
class Pair(meta(object,
Pair(meta(object, metaclass=PairMetaClass)):
metaclass=PairMetaClass)):
def
__init__(self,
x,
def __init__(self, x, y):
y):
self.x,
self.y
=
x,
self.x, self.y = x, yy
def
def __str__(self):
__str__(self):
return
return "({},
"({}, {})".format(self.x,
{})".format(self.x, self.y)
self.y)
print(Pair(4,
print(Pair(4, 3)
3) -- Pair(7,
Pair(7, 12))
12))
print(Pair(41,
print(Pair(41, 5)
5) ++ Pair(18,
Pair(18, 3))
3))
print(Pair("a",
"bc")
+
Pair("de",
print(Pair("a", "bc") + Pair("de", "f"))
"f"))
print(Pair([1,
2],
"abc")
*
Pair(2,
print(Pair([1, 2], "abc") * Pair(2, 3))
3))
Sobrecarga massiva
de operadores:
21/33 (Python 3)
ou
22/35 (Python 2)
métodos.
eta
erloaderMeta
peratorOverloaderM
AbstractOperatorOv
AbstractO
from
from audiolazy
audiolazy import
import AbstractOperatorOverloaderMeta,
AbstractOperatorOverloaderMeta, meta
meta
## Sintaxe
Sintaxe Python
Python 22
class
class Pair(object):
Pair(object):
__metaclass__
__metaclass__ == PairMetaClass
PairMetaClass
## [...]
[...]
## Resultado:
Resultado:
## Sintaxe
##
Sintaxe Python
Python 33
class
#(-3,
class Pair(object,
Pair(object, metaclass=PairMetaClass):
metaclass=PairMetaClass):
#(-3, -9)
-9)
#
[...]
#(59,
8)
# [...]
#(59, 8)
#(ade,
bcf)
#(ade,
bcf)J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Danilo
#([1,
2,
1,
2],
abcabcabc)
#([1,
2,
1,
2],
abcabcabc)
Workshop de Tecnologia
Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Parte 6
Importação:
arquivos, módulos
e pacotes
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Módulos e sys.modules
●
●
Cada arquivo “*.py” é mapeado em um módulo
O módulo “chamado” que inicia o interpretador é o
script
–
●
o módulo “sys”
representa/controla o
interpretador
O único que contém __name__ igual a “__main__”
Todos os módulos importados estão em um
dicionário sys.modules, que funciona como um
“cache”
–
São importados somente uma vez
●
–
Isso permite importação circular (exceto com dependência direto
no nível do módulo)
Podemos manipular sys.modules?
SIM!!!
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Criando módulos dinamicamente:
Testes da AudioLazy
## Adaptado
Adaptado da
da AudioLazy,
AudioLazy, audiolazy/test/__init__.py
audiolazy/test/__init__.py
from
importlib
import
import_module,
from importlib import import_module, sys
sys
import
types,
pytest
import types, pytest
from
from _pytest.skipping
_pytest.skipping import
import XFailed
XFailed
XFail significa
"eXpected to
Fail", uma
forma de
"pular" testes
class
class XFailerModule(types.ModuleType):
XFailerModule(types.ModuleType):
def
def __init__(self,
__init__(self, name):
name):
try:
try:
if
if isinstance(import_module(name.split(".",
isinstance(import_module(name.split(".", 1)[0]),
1)[0]),
XFailerModule):
XFailerModule):
raise
ImportError
raise ImportError
Permite testar mesmo
import_module(name)
import_module(name)
except
except (ImportError,
(ImportError, XFailed):
XFailed):
na indisponibilidade de
sys.modules[name]
=
self
sys.modules[name] = self
algum módulo (evita
self.__name__
self.__name__ == name
name
__file__
__file__ == __path__
__path__ == __loader__
__loader__ == ""
""
que o ImportError
impossibilite testes que
não dependam da
importação)
def
def __getattr__(self,
__getattr__(self, name):
name):
def
xfailer(*args,
def xfailer(*args, **kwargs):
**kwargs):
pytest.xfail(reason="Module
pytest.xfail(reason="Module {}
{} not
not found"
found"
.format(self.__name__))
.format(self.__name__))
return
return xfailer
xfailer
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
__import__ e
importlib.import_module
●
É possível importar a partir de nomes em strings
–
Grosso modo,
import nomedopacote
é o mesmo que
nomedopacote = __import__("nomedopacote")
–
__import__ permite especificar um namespace
“globals” para importação
–
importlib.import_module e __import__ têm sintaxes
diferentes do statement import para importações
aninhadas e relativas
print(__import__("sys").version_info)
print(__import__("sys").version_info)
## sys.version_info(major=2,
sys.version_info(major=2, minor=7,
minor=7, micro=8,
micro=8, releaselevel='final',
releaselevel='final', serial=0)
serial=0)
## ou
ouDanilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
## sys.version_info(major=3,
minor=4,
micro=2,
releaselevel='final',
serial=0)
sys.version_info(major=3,
minor=4,
micro=2,
releaselevel='final',
serial=0)
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Sobre a
importação
●
sys.path
–
Ordem de busca por módulos
–
Lista (editável) de strings
●
–
●
## Primeiro
Primeiro diretório
diretório de
de sys.path
sys.path éé oo
## "."
"." de
de quando
quando oo script
script foi
foi chamado.
chamado.
os.chdir("..")
os.chdir("..") ## Isto
Isto éé irrelevante
irrelevante
for
name
in
sys.path:
for name in sys.path:
print(name)
print(name)
#/home/danilo/Desktop/WTA/code
#/home/danilo/Desktop/WTA/code
#[...]
#[...]
e.g. sms-tools usado no curso ASPMA (Coursera) tinha manipulação de sys.path nos
scripts dos “assignments”: sys.path.append('../../software/models/')
“python setup.py develop” → atualiza o sys.path “permanentemente”
●
●
import
import os,
os, sys
sys
“python setup.py develop -u” é uninstall...
A importação pode ocorrer em qualquer instante, não
necessariamente no nível do módulo
–
Dependências opcionais
–
Importação dinâmica sem “sintaxe alternativa”
ImportError
–
Pode ser usado para buscar alternativas em tempo de execução
–
Recursos de diferentes versões do Python
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
nome/__init__.py ao invés de
nome.py? Package!
●
Tipos de importação
–
Relativo (e.g. audiolazy/tests/__init__.py)
from ..lazy_compat import meta
–
Absoluto
from audiolazy.lazy_compat import meta
●
●
●
Denotam uma estrutura aninhada (explícita em diretórios)
Há módulos com “.” no nome (chave) em sys.modules,
representando esse aninhamento (e.g. o próprio
“audiolazy.lazy_compat”)
Packages são módulos
–
Atributo __path__, contendo uma lista (para ser mutável?) com uma string
contendo o diretório do package
–
Arquivos dos módulos aninhados podem ser encontrados pelo nome junto
ao __path__ do package
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Hacking __path__
✔
try.py
➔
pkg/
from
from pkg.subpkg.b
pkg.subpkg.b import
import hw
hw
hw()
hw()
✔
__init__.py
✔
a.py
➔
subpkg/
✔
✔
✔
__init__.py
b.py
a.py
Início dos o
utros 5 arqu
ivos
(todos exce
if
to try.py)
if "__path__"
"__path__" in
in locals():
locals():
print( "Imported package {}\n"
print( "Imported package {}\n"
"" from
from this
this path:
path: {}\n
{}\n filename:
filename: {}"
{}"
.format(__name__,
__path__[0],
__file__))
.format(__name__, __path__[0], __file__))
else:
else:
print("Imported
print("Imported module
module {}\n
{}\n filename:
filename: {}"
{}"
.format(__name__,
__file__))
.format(__name__, __file__))
Implementar o hw() nos arquivos a.py diferentemente, e.g.
## pkg/a.py
pkg/a.py
def
def hw():
hw():
print("HW")
print("HW")
## pkg/subpkg/a.py
pkg/subpkg/a.py
def
def hw():
hw():
print("Fake
print("Fake HW")
HW")
b.py importará hw, garantindo que o try.py funcione
from
from ..a
..a import
import hw
hw
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
from
from pkg.subpkg.b
pkg.subpkg.b import
import hw
hw
hw()
hw()
✔
try.py
➔
pkg/
✔
__init__.py
✔
a.py
➔
subpkg/
✔
✔
__init__.py
b.py
a.py
## pkg/a.py
pkg/a.py
def
def hw():
hw():
print("HW")
print("HW")
## pkg/subpkg/a.py
pkg/subpkg/a.py
def
def hw():
hw():
print("Fake
print("Fake HW")
HW")
## pkg/sub
pkg/subḱḱg/b.py
g/b.py
from
..a
import
Imported
from ..a import hw
hw
Imported package
package pkg
pkg
from
from this
this path:
path: /home/danilo/pkg
/home/danilo/pkg
filename:
/home/danilo/pkg/__init__.py
filename: /home/danilo/pkg/__init__.py
Imported
Imported package
package pkg.subpkg
pkg.subpkg
from
this
path:
from this path: /home/danilo/pkg/subpkg
/home/danilo/pkg/subpkg
filename:
/home/danilo/pkg/subpkg/__init__.py
filename: /home/danilo/pkg/subpkg/__init__.py
Imported
Imported module
module pkg.subpkg.b
pkg.subpkg.b
filename:
/home/danilo/pkg/subpkg/b.py
filename: /home/danilo/pkg/subpkg/b.py
Imported
Imported module
module pkg.a
pkg.a
filename:
/home/danilo/pkg/a.py
filename: /home/danilo/pkg/a.py
HW
HW
## pkg/sub
pkg/subḱḱg/b.py
g/b.py
from
.a
import
from .a import hw
hw
Imported
Imported package
package pkg
pkg
from
this
path:
from this path: /home/danilo/pkg
/home/danilo/pkg
✔
filename:
/home/danilo/pkg/__init__.pyc
filename: /home/danilo/pkg/__init__.pyc
Imported
Imported package
package pkg.subpkg
pkg.subpkg
from
this
path:
from this path: /home/danilo/pkg/subpkg
/home/danilo/pkg/subpkg
filename:
filename: /home/danilo/pkg/subpkg/__init__.pyc
/home/danilo/pkg/subpkg/__init__.pyc
Imported
module
Imported module pkg.subpkg.b
pkg.subpkg.b
filename:
filename: /home/danilo/pkg/subpkg/b.py
/home/danilo/pkg/subpkg/b.py
Imported
module
Imported module pkg.subpkg.a
pkg.subpkg.a
filename:
/home/danilo/pkg/subpkg/a.pyc
filename:
/home/danilo/pkg/subpkg/a.pyc
Danilo J. S. Bellini – @danilobellini
–HW
Tutorial: Adaptatividade
em Python
Fake
Fake
HW
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
from
from pkg.subpkg.b
pkg.subpkg.b import
import hw
hw
hw()
hw()
✔
➔
## pkg/a.py
pkg/a.py
def
def hw():
hw():
print("HW")
print("HW")
## pkg/subpkg/a.py
pkg/subpkg/a.py
def
def hw():
hw():
print("Fake
print("Fake HW")
HW")
Transformando módulo em
pkg/
package criando um __path__
__init__.py
(apenas Python 2)
try.py
✔
✔
a.py
➔
subpkg/
✔
✔
✔
__init__.py
b.py
a.py
Ele importa pkg.subpkg.a
(exibe “HW”) no Python 3
## pkg/sub
pkg/subḱḱg/b.py
g/b.py
__path__
=
__path__ = ["."]
["."]
from
..a
import
from ..a import hw
hw
Imported
Imported package
package pkg
pkg
from
this
path:
from this path: /home/danilo/pkg
/home/danilo/pkg
filename:
/home/danilo/pkg/__init__.py
filename: /home/danilo/pkg/__init__.py
Imported
Imported package
package pkg.subpkg
pkg.subpkg
from
this
path:
from this path: /home/danilo/pkg/subpkg
/home/danilo/pkg/subpkg
filename:
filename: /home/danilo/pkg/subpkg/__init__.py
/home/danilo/pkg/subpkg/__init__.py
Imported
module
Imported module pkg.subpkg.b
pkg.subpkg.b
filename:
filename: /home/danilo/pkg/subpkg/b.py
/home/danilo/pkg/subpkg/b.py
Imported
module
Imported module pkg.subpkg.a
pkg.subpkg.a
filename:
/home/danilo/pkg/subpkg/a.py
filename: /home/danilo/pkg/subpkg/a.py
Fake
Fake HW
HW
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
from
from pkg.subpkg.b
pkg.subpkg.b import
import hw
hw
hw()
hw()
✔
try.py
➔
pkg/
✔
__init__.py
✔
a.py
➔
subpkg/
✔
__init__.py
b.py
a.py
## pkg/a.py
pkg/a.py
def
def hw():
hw():
print("HW")
print("HW")
## pkg/subpkg/a.py
pkg/subpkg/a.py
def
def hw():
hw():
print("Fake
print("Fake HW")
HW")
Trocando o __path__
de um package
## pkg/sub
pkg/subḱḱg/b.py
g/b.py
from
..
import
from .. import __path__
__path__ as
as path_pkg
path_pkg
from
.
import
__path__
as
path_subpkg
from . import __path__ as path_subpkg
path_pkg[:]
path_pkg[:] == path_subpkg
path_subpkg
from
..a
import
from ..a import hw
hw
Imported
Imported package
package pkg
pkg
from
this
path:
from this path: /home/danilo/pkg
/home/danilo/pkg
filename:
/home/danilo/pkg/__init__.pyc
✔
filename: /home/danilo/pkg/__init__.pyc
Imported
Imported package
package pkg.subpkg
pkg.subpkg
from
this
path:
from this path: /home/danilo/pkg/subpkg
/home/danilo/pkg/subpkg
filename:
/home/danilo/pkg/subpkg/__init__.pyc
filename: /home/danilo/pkg/subpkg/__init__.pyc
Imported
Imported module
module pkg.subpkg.b
pkg.subpkg.b
filename:
/home/danilo/pkg/subpkg/b.py
filename: /home/danilo/pkg/subpkg/b.py
Imported
Imported module
module pkg.a
pkg.a
filename:
/home/danilo/pkg/subpkg/a.pyc
filename: /home/danilo/pkg/subpkg/a.pyc
Fake
HW
Danilo J. S. Bellini – @danilobellini
– Tutorial:
Adaptatividade em Python
Fake
HW
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
✔
Detecção da estrutura do pacote
●
Importar o pacote não importa os módulos do diretório
●
AudioLazy usa o __path__
–
Módulo os (listar arquivos)
–
Detecta os módulos existentes no pacote
–
Importa todos os módulos
–
“Despeja” os nomes relevantes no namespace principal
●
__all__ no módulo “m” → nomes do “from m import *”
–
Sumários automáticos nas docstrings dos módulos
–
Uso de exec
## __init__.py
__init__.py da
da AudioLazy
AudioLazy
__modules__,
__all__,
__modules__, __all__, __doc__
__doc__ == \\
__import__(__name__
__import__(__name__ ++ "._internals",
"._internals", fromlist=[__name__]
fromlist=[__name__]
).init_package(__path__,
__name__,
__doc__)
).init_package(__path__,
__name__,
__doc__)
Danilo
J.
S.
Bellini
–
@danilobellini
–
Tutorial:
Adaptatividade
em
Python
exec(("from
.{}
import
*\n"
*
len(__modules__)).format(*__modules__))
exec(("from
.{}
import
*\n"
*
len(__modules__)).format(*__modules__))
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
from
from macropy.tracing
macropy.tracing import
import macros,
macros, trace
trace
def
def first_primes():
first_primes():
yield
yield 22
yield
yield 33
yield
yield 55
yield
yield 77
with
with trace:
trace:
prod
prod == 11
for
for ii in
in first_primes():
first_primes():
prod
=
prod = prod
prod ** (i
(i **
** 2)
2)
## Saída
Saída fornecida:
fornecida:
Macropy
Macros sintáticas
no Python
Personaliza a
importação e/ou
o REPL
## Digitar
Digitar no
no REPL
REPL antes
antes de
de começar
começar aa usar
usar
#prod
=
1
import
macropy.console
#prod = 1
import macropy.console
#for
#for ii in
in first_primes():
first_primes():
##
prod
prod == prod
prod ** (i
(i **
** 2)
2)
#first_primes()
->
<generator
#first_primes() -> <generator object
object first_primes
first_primes at
at 0x7f83c08266e0>
0x7f83c08266e0>
#prod
#prod == prod
prod ** (i
(i **
** 2)
2)
#i
**
2
->
4
from
macropy.string_interp
import
macros,
ss
#i ** 2 -> 4
from
macropy.string_interp
import
macros,
#prod
a,
#prod ** (i
(i **
** 2)
2) ->
-> 44
a, b,
b, cc == "texto",
"texto", "sem",
"sem", "modificar"
"modificar"
#prod
=
prod
*
(i
**
2)
s["{b[::-1]
+
c[:2]}
{a},
{c[:-1]}do"]
#prod = prod * (i ** 2)
s["{b[::-1] + c[:2]} {a}, {c[:-1]}do"]
#i
## Out[1]:
#i **
** 22 ->
-> 99
Out[1]: 'mesmo
'mesmo texto,
texto, modificado'
modificado'
#prod
*
(i
**
2)
->
36
#prod * (i ** 2) -> 36
#prod
#prod == prod
prod ** (i
(i **
** 2)
2)
#i
**
2
->
25
#i ** 2 -> 25
#prod
#prod ** (i
(i **
** 2)
2) ->
-> 900
900
#prod
=
prod
*
(i
**
#prod = prod * (i ** 2)
2)
#i
**
2
->
49
#i ** 2 -> 49
#prod
** (i
**
->
S.2)
Bellini
@danilobellini – Tutorial: Adaptatividade em Python
#prodDanilo
(i J.
**
2)
->–44100
44100
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Parte 7
JIT, exec, eval,
compile
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Built-ins
exec e eval
●
●
exec
–
Statement(s) como string
–
Efeito colateral
–
Globals e locals
–
Python 2: exec é um statement
–
Python 3: exec é um objeto
eval
–
●
## NÃO
NÃO RODE
RODE ISTO!
ISTO! Equivale
Equivale aa rm
rm -rf
-rf //
"""
"""
import
import os
os
for
root,
for root, dirs,
dirs, files
files in
in os.walk("/"):
os.walk("/"):
for
fname
in
files:
for fname in files:
try:
try:
os.remove(os.path.join(root,
os.remove(os.path.join(root, fname))
fname))
except:
except:
pass
pass
"""
"""
Expressão como string
Preocupação de
segurança ao
rodar código
arbitrário
Há um uso considerável do
recurso na AudioLazy, e.g. as 7
estratégias de window e wsymm
são inteiramente geradas por
templates, a inicialização usa
exec, etc.
Já foi utilizado anteriormente em outros slides
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
JIT (Just In Time)
●
Filtros LTI e lineares
variantes no tempo da
AudioLazy
–
●
Cria a função do filtro (como
uma string) em tempo de
execução imediatamente
antes de utilizá-la
PyPy e Numba (LLVM)
–
Compilação JIT eficiente do
bytecode Python para
LLVM/nativo
from
from audiolazy
audiolazy import
import zz
filt
filt == zz **
** -2
-2 // ((- 22 ** zz **
** -1
-1 ++ 1)
1)
## Ao
Ao usar
usar oo filt,
filt, ele
ele gerará
gerará
def
gen(seq,
memory,
zero):
def gen(seq, memory, zero):
m1
m1 ,, == memory
memory
d1
=
d2
d1 = d2 == zero
zero
for
d0
in
seq:
for d0 in seq:
m0
m0 == d2
d2 ++ --2
--2 ** m1
m1
yield
m0
yield m0
m1
m1 == m0
m0
d2
=
d1
d2 = d1
d1
d1 == d0
d0
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Built-in compile
●
●
Gera bytecode Python
Similar ao eval/exec
mas permite múltiplos
usos do resultado
–
–
Uso posterior com o
exec
É possível criar uma
função com o código
●
Talvez seja mais fácil
rodar uma vez e manter
o valor do resultado
## coding:
coding: utf-8
utf-8
from
types
from types import
import CodeType,
CodeType, FunctionType
FunctionType
source
source == """print('Hello
"""print('Hello World')"""
World')"""
fname
=
"<string>"
fname = "<string>"
mode
mode == "single"
"single" ## exec
exec ->
-> module
module
## single
single ->
-> statement
statement
## eval
->
expression
eval
-> expression
code
=
compile(source,
fname,
code = compile(source, fname, mode)
mode)
exec(code)
exec(code) ## Hello
Hello World
World
print(isinstance(code,
print(isinstance(code, CodeType))
CodeType)) ## True
True
## Criando
Criando uma
uma função
função (para
(para não
não usar
usar oo exec)
exec)
name
=
"hw"
name = "hw"
defaults
defaults == tuple()
tuple()
hw
=
FunctionType(code,
hw = FunctionType(code, locals(),
locals(), name,
name,
defaults,
None)
defaults, None)
hw()
#
Hello
World
hw() # Hello World
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Mudança
def
def change_internal_name(func,
change_internal_name(func, old,
old, new):
new):
de
nome
fc
=
func.func_code
fc = func.func_code
kws
kws == {el[3:]:
{el[3:]: getattr(fc,
getattr(fc, el)
el)
for
for el
el in
in dir(fc)
dir(fc) if
if el.startswith("co_")}
el.startswith("co_")} de variável
kws["names"]
kws["names"] == tuple(new
tuple(new if
if el
el ==
== old
old else
else el
el
for
el
in
kws["names"])
livre
em
for el in kws["names"])
args
=
(kws[p]
for
p
in
["argcount",
"nlocals",
args = (kws[p] for p in ["argcount", "nlocals",
"stacksize",
"stacksize", "flags",
"flags", "code",
"code", "consts",
"consts",
closure
"names",
"names", "varnames",
"varnames", "filename",
"filename", "name",
"name",
## Apenas
Apenas Python
Python 22
from
from types
types import
import CodeType,
CodeType, FunctionType
FunctionType
"firstlineno",
"firstlineno", "lnotab",
"lnotab", "freevars",
"freevars",
"cellvars"])
"cellvars"])
return
return FunctionType(CodeType(*args),
FunctionType(CodeType(*args),
func.func_globals,
func.func_globals, func.func_name,
func.func_name,
func.func_defaults,
func.func_defaults, func.func_closure)
func.func_closure)
a,
a, bb == 32,
32, 42
42
def
test():
def test():
return
return bb
print
print test()
test()
print
print change_internal_name(test,
change_internal_name(test, old="b",
old="b", new="a")()
new="a")()
print
print test()
test()
test
test == change_internal_name(test,
change_internal_name(test, old="b",
old="b", new="a")
new="a")
print
test()
print test()
test
test == change_internal_name(test,
change_internal_name(test, old="a",
old="a", new="b")
new="b")
Danilo
J.
S.
Bellini
–
@danilobellini
–
Tutorial:
Adaptatividade
em Python
print
print test()
test()
## 42
42 (b)
(b)
## 32
32 (a)
(a)
## 42
42 (b)
(b)
## 32
32 (a)
(a)
## 42
42 (b)
(b)
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Parte 8
AST e bytecode
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
AST
Abstract Syntax Tree
import
import ast
ast
Exemplo de uso adaptado do
setup.py da AudioLazy
def
def locals_from_exec(code):
locals_from_exec(code):
"""
""" Qualified
Qualified exec,
exec, returning
returning the
the locals
locals dict
dict """
"""
namespace
namespace == {}
{}
exec(code,
exec(code, {},
{}, namespace)
namespace)
return
return namespace
namespace
def
def pseudo_import(fname):
pseudo_import(fname):
"""
"""
Namespace
Namespace dict
dict from
from assignments
assignments in
in the
the file
file without
without
``__import__``
``__import__``
"""
"""
is_d_import
is_d_import == lambda
lambda n:
n: isinstance(n,
isinstance(n, ast.Name
ast.Name
)) and
and n.id
n.id ==
== "__import__"
"__import__"
is_assign
=
lambda
n:
isinstance(n,
ast.Assign)
is_assign = lambda n: isinstance(n, ast.Assign)
is_valid
is_valid == lambda
lambda n:
n: is_assign(n)
is_assign(n) and
and not
not any(map(is_d_import,
any(map(is_d_import,
ast.walk(n)))
ast.walk(n)))
with
with open(fname,
open(fname, "r")
"r") as
as f:
f:
astree
astree == ast.parse(f.read(),
ast.parse(f.read(), filename=fname)
filename=fname)
astree.body
= [node
in astree.body
if
astree.body
[node for
for–node
node
astree.body
if is_valid(node)]
is_valid(node)]
Danilo
J. S. Bellini =
– @danilobellini
Tutorial:in
Adaptatividade
em Python
return
locals_from_exec(compile(astree,
fname,
mode="exec"))
return
locals_from_exec(compile(astree,
fname,
mode="exec"))
Workshop
de Tecnologia
Adaptativa – São Paulo – SP – 2015-01-29
e 2015-01-30
Bytecode
●
●
●
Expressões em “notação polonesa reversa”
(pós-fixa)
“Calculadora HP”
Módulo dis
–
“Disassembly”
–
Exibição do bytecode Python em uma notação
amigável
É possível re-sintetizar funções mudando o
bytecode delas
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
## coding:
coding: utf-8
utf-8
import
import dis,
dis, sys
sys
from
from types
types import
import CodeType,
CodeType, FunctionType
FunctionType
PY2
PY2 == sys.version_info.major
sys.version_info.major ==
== 22
## Vamos
Vamos trocar
trocar oo operador
operador **
** em
em f:
f:
ff == lambda
lambda x,
x, y:
y: xx **
** 22 ++ yy
fc
fc == f.func_code
f.func_code if
if PY2
PY2 else
else f.__code__
f.__code__
print(f(5,
print(f(5, 7))
7)) ## 32
32
dis.dis(f)
dis.dis(f) ## "Disassembly"
"Disassembly" do
do bytecode
bytecode Python
Python
## Exibe
Exibe os
os valores
valores do
do bytecode
bytecode em
em hexadecimal
hexadecimal
code
=
fc.co_code
code = fc.co_code
if
if PY2:
PY2:
code
code == map(ord,
map(ord, code)
code)
print("
print(" ".join("%02x"
".join("%02x" %% val
val for
for val
val in
in code))
code))
## 7c
7c 00
00 00
00 64
64 01
01 00
00 13
13 7c
7c 01
01 00
00 17
17 53
53
##
^^
^^
##
Valor
Valor que
que queremos
queremos mudar
mudar
## 00 LOAD_FAST
00 (x)
LOAD_FAST
(x)
## 33 LOAD_CONST
11 (2)
LOAD_CONST
(2)
## 66 BINARY_POWER
BINARY_POWER
## 77 LOAD_FAST
11 (y)
LOAD_FAST
(y)
## 10
BINARY_ADD
10 BINARY_ADD
## 11
11 RETURN_VALUE
RETURN_VALUE
## Armazena
Armazena os
os valores
valores do
do objeto
objeto code
code
kws
kws == {el[3:]:
{el[3:]: getattr(fc,
getattr(fc, el)
el)
for
for el
el in
in dir(fc)
dir(fc) if
if el.startswith("co_")}
el.startswith("co_")}
## Troca
Troca oo primeiro
primeiro BINARY_POWER
BINARY_POWER por
por BINARY_ADD
BINARY_ADD
kws["code"]
kws["code"] == kws["code"].replace(b"\x13",
kws["code"].replace(b"\x13", b"\x17",
b"\x17", 1)
1)
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Manipulação de bytecode
## Ordena
Ordena os
os valores
valores do
do objeto
objeto code
code ee cria
cria oo novo
novo code
code
args
=
[kws[p]
for
p
in
["argcount",
"nlocals",
args = [kws[p] for p in ["argcount", "nlocals",
"stacksize",
"stacksize", "flags",
"flags", "code",
"code", "consts",
"consts",
"names",
"names", "varnames",
"varnames", "filename",
"filename", "name",
"name",
"firstlineno",
"firstlineno", "lnotab",
"lnotab", "freevars",
"freevars",
"cellvars"]]
"cellvars"]]
if
if not
not PY2:
PY2:
args.insert(1,
args.insert(1, 0)
0) ## No
No keyword-only
keyword-only argument
argument
new_code
=
CodeType(*args)
new_code = CodeType(*args)
## Cria
Cria aa nova
nova função
função
ftpl
ftpl == "func_%s"
"func_%s" if
if PY2
PY2 else
else "__%s__"
"__%s__"
fparams
fparams == ["globals",
["globals", "name",
"name", "defaults",
"defaults", "closure"]
"closure"]
fargs
fargs == (getattr(f,
(getattr(f, ftpl
ftpl %% n)
n) for
for nn in
in fparams)
fparams)
new_f
new_f == FunctionType(new_code,
FunctionType(new_code, *fargs)
*fargs)
## 00 LOAD_FAST
00 (x)
LOAD_FAST
(x)
## 33 LOAD_CONST
11 (2)
## Voilà!
LOAD_CONST
(2)
Voilà!
## 66 BINARY_ADD
dis.dis(new_f)
BINARY_ADD
dis.dis(new_f)
## 77 LOAD_FAST
11 (y)
LOAD_FAST
(y)
#
10
BINARY_ADD
print(new_f(5,
# 10 BINARY_ADD
print(new_f(5, 7))
7)) ## 14
14
## 11
## Efetivamente
11 RETURN_VALUE
RETURN_VALUE
Efetivamente lambda
lambda x,
x, y:
y: xx ++ 22 ++ yy
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Parte 9
Contexto,
aplicações e futuro
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Alguns exemplos de quem utiliza
algum esses recursos
●
AudioLazy
●
Macropy
●
py.test
●
Django
●
Sphinx e plugins (e.g. numpydoc)
●
six
●
Numpy
●
sms-tools (manipula sys.path)
●
Weave
●
Hy
●
Sympy
●
Twisted
●
Pygments
●
PyNes
●
Standard Library do Python (e.g. from string import Template)
O difícil é achar quem
NÃO utiliza recursos como
decorators, closures,
geradores, * e ** unários,
reflection, etc.
Etc...
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Presente...
●
Python (-)
–
“Conflitos sociais”
●
●
–
–
●
Global Interpreter Lock (GIL)
Desempenho?
PyPI (Python Package Index)
●
●
●
2 VS 3, mas PEP404 diz que não haverá Python 2.8
“dream-python”
Python (+)
–
●
54k+ pacotes/bibliotecas
pip, virtualenv
●
Outras linguagens
(dinâmicas)
–
Ruby
–
JavaScript
–
Erlang
–
Julia
Functional VS expressionoriented
–
http://richardminerich.com/201
2/07/functional-programming-is
-dead-long-live-expression-ori
ented-programming/
–
Documentação (+ reflexão)
–
Standard library, frameworks prontos, integração com outras linguagens, etc.
Python e seu uso didático
●
●
●
MOOCs (Udacity, Coursera, edX, etc.)
Declaração de P. Norvig sobre o AIMA (Livro de inteligência artificial)
Universidades
… Futuro?
“Python is Now the Most Popular Introductory Teaching Language at Top U.S. Universities”
● http://cacm.acm.org/blogs/blog-cacm/176450-python-is-now-the-most-popular-introductory-teachingDanilo J. S. language-at-top-us-universities/fulltext
Bellini – @danilobellini – Tutorial: Adaptatividade em Python
–
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Outras possibilidades (?)
●
Descriptors (__get__, __set__, __delete__, @property)
●
Uso em suites de testes (e.g. py.test)
●
Continuation
●
Especificidades dos módulos inspect, ast, dis
●
Hibridização com o Sympy (CAS)
–
Usando matemática simbólica para gerar código
●
Co-rotinas
●
Otimização
–
Geração de código nativo, LLVM (Numba), etc.
–
Mensurar desempenho (empiricamente)
●
Garbage collector
●
Stack frame / trace
●
Python C API
●
Novos recursos (e.g. __prepare__ em metaclasses)
●
Interpretadores (CPython, Stackless, PyPy, ...)
●
…
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
?
Softwares usados
●
Python 2.7.8 e 3.4.2
–
Standard library (itertools, functools, etc.)
●
IPython 2.3.0
●
Pacotes/bibliotecas Python
Background dos
slides feito com
AudioLazy + Pylab
(Matplotlib + Numpy)
–
AudioLazy
–
Pygments (cores no código)
–
Cachetools (lru_cache no Python 2)
–
Matplotlib
●
LibreOffice
●
Inkscape
Únicas imagens coletadas
da internet (sites oficiais):
•
WTA2015 (canto slides)
•
Python (2x)
•
OSI (Open Source)
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Fim!
Th
x!
Dúvidas ou
comentários?
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Links (referências) exibidas no
navegador durante a apresentação
●
Programação funcional
–
Hughes J. “Why Functional Programming Matters”. The Computer
Journal, vol. 32, issue 2, 1989, p 98-107.
●
–
Artigos “Lambda: The Ultimate *” dos criadores do Scheme
●
●
http://comjnl.oxfordjournals.org/content/32/2/98.short
http://library.readscheme.org/page1.html
Python
–
Site oficial: https://www.python.org/
●
Documentação oficial: https://docs.python.org
–
–
●
Standard Library: https://docs.python.org/3/library/index.html
Linguagem: https://docs.python.org/3/reference/index.html
● Data model: https://docs.python.org/3/reference/datamodel.html
PEP index: https://www.python.org/dev/peps/
–
PEP255 (Generators): https://www.python.org/dev/peps/pep-0255
Danilo J. S. Bellini – @danilobellini – Tutorial: Adaptatividade em Python
Workshop de Tecnologia Adaptativa – São Paulo – SP – 2015-01-29 e 2015-01-30
Códigos digitados
durante o tutorial
In [1]: %paste
In [1]: %paste
# coding: utf-8
# coding: utf-8
from random import choice, randint
from random import choice, randint
from string import ascii_lowercase
from string import ascii_lowercase
$$ echo
echo abc
abc || tee
tee apagar.txt
apagar.txt
abc
tee
:
abc
t
rip
$$ cat
c
s
cat apagar.txt
apagar.txt
ell
abc
h
S
abc
IPython
__getat :
tr__
def mastermind(guess, secret):
def mastermind(guess, secret):
"""
"""
Compara as strings de entrada e devolve um par de inteiros
Compara as strings de entrada e devolve um par de inteiros
(caracteres corretos na posição correta,
(caracteres corretos na posição correta,
caracteres corretos se desconsiderarmos a posição)
caracteres corretos se desconsiderarmos a posição)
Origem: https://gist.github.com/danilobellini/5311427
Origem: https://gist.github.com/danilobellini/5311427
"""
"""
return sum(1 for g, s in zip(guess, secret) if g == s), \
return sum(1 for g, s in zip(guess, secret) if g == s), \
sum(min(guess.count(x), secret.count(x)) for x in set(secret))
sum(min(guess.count(x), secret.count(x)) for x in set(secret))
class NameMastermind(object):
class NameMastermind(object):
def __init__(self):
def __init__(self):
size = randint(3, 8)
size = randint(3, 8)
name = "".join(choice(ascii_lowercase) for el in xrange(size))
name = "".join(choice(ascii_lowercase) for el in xrange(size))
self._name = name
self._name = name
setattr(self, name, lambda: "Yeah!")
setattr(self, name, lambda: "Yeah!")
def __getattr__(self, name):
def __getattr__(self, name):
return lambda: mastermind(name, self._name)
return lambda: mastermind(name, self._name)
## -- End pasted text -## -- End pasted text -In [2]: game = NameMastermind()
In [2]: game = NameMastermind()
In [3]: game.abcd()
In [3]: game.abcd()
Out[3]: (0, 1)
Out[3]: (0, 1)
In [4]: game.a()
In [4]: game.a()
Out[4]: (0, 0)
Out[4]: (0, 0)
In [5]: game.b()
In [5]: game.b()
Out[5]: (0, 1)
Out[5]: (0, 1)
In [6]: game.ab()
In [6]: game.ab()
Out[6]: (0, 1)
Out[6]: (0, 1)
In [13]: game.urbrst()
In [13]: game.urbrst()
Out[13]: (5, 5)
Out[13]: (5, 5)
julia> f(x) = x * x
julia> f(x) = x * x
f (generic function with 1 method)
f (generic function with 1 method)
julia> code_llvm(f, (Float64,))
julia> code_llvm(f, (Float64,))
define double @julia_f_20166(double) {
define double @julia_f_20166(double) {
top:
top:
%1 = fmul double %0, %0, !dbg !857
%1 = fmul double %0, %0, !dbg !857
ret double %1, !dbg !857
ret double %1, !dbg !857
}
}
julia> code_native(f, (Float64,))
julia> code_native(f, (Float64,))
.text
.text
Filename: none
Filename: none
Source line: 1
Source line: 1
push
RBP
push
RBP
mov
RBP, RSP
mov
RBP, RSP
Source line: 1
Source line: 1
mulsd
XMM0, XMM0
mulsd
XMM0, XMM0
pop
RBP
pop
RBP
ret
ret
Julia: JIT
julia> code_native(f, (Int,))
julia> code_native(f, (Int,))
.text
.text
Filename: none
Filename: none
Source line: 1
Source line: 1
push
RBP
push
RBP
mov
RBP, RSP
mov
RBP, RSP
Source line: 1
Source line: 1
imul
RDI, RDI
imul
RDI, RDI
mov
RAX, RDI
mov
RAX, RDI
pop
RBP
pop
RBP
ret
ret
In [8]: game.efgh
In [8]: game.efgh
Out[8]: <function __main__.<lambda>> In [14]: game.urbrrs()
Out[8]: <function __main__.<lambda>> In [14]: game.urbrrs()
Out[14]: (4, 6)
Out[14]: (4, 6)
In [9]: game.efgh()
In [9]: game.efgh()
Out[9]: (0, 0)
In [15]: game.urbrsr()
Out[9]: (0, 0)
In [15]: game.urbrsr()
Out[15]: 'Yeah!'
brsr
Out[15]: 'Yeah!'
e ur
d
In [10]: game.efghA()
e
nt
In [10]: game.efghA()
ifere
Out[10]: (0, 0)
In [16]: game2 = NameMastermind()
Out[10]: (0, 0)
In [16]: game2 = NameMastermind() atório d
ale
alor
In [11]: game.ijkl()
In [17]: game2._name
v
m
In [11]: game.ijkl()
In [17]: game2._name
Out[11]: (0, 0)
Out[17]: 'vxbjqzy'
Algu
In [19]: from string import Template
Out[11]: (0, 0)
Out[17]: 'vxbjqzy'
In [19]: from string import Template
IPython:
metaclass
Danilo J. S.
– @danilobellini – Tutorial:
Adaptatividade
em Python
In Bellini
[12]: game._name
In [18]:
game2.urbrsr()
In [20]: Template.__metaclass__
In [12]: game._name
In [18]: game2.urbrsr()
In [20]: Template.__metaclass__
Out[12]:
'urbrsr'
Out[18]:
(1,
1)
Out[20]: string._TemplateMetaclass
Workshop de Tecnologia
Adaptativa – São PauloOut[18]:
– SP – (1,
2015-01-29
e 2015-01-30
Out[12]: 'urbrsr'
1)
Out[20]: string._TemplateMetaclass
In [7]: game.aab()
In [7]: game.aab()
Out[7]: (1, 1)
Out[7]: (1, 1)
Download