Aula 30
1 Lei de benford
funcao que recebe 1 string e imprime a proporcão que cada um dos digitos (1 a 9) aparece no texto como o primeiro digito de um numero - essa é a verdadeira lei de Benford - nao a que implementamos em haskell
2 OO em python
class C: def __init__(self,...) def __repl__(self) def __str__(self) def __eq__(self, other) self == other? def __add__(self,other) self + other
uso mais comum de objetos em bibliotecas Python - para guardar um estado aprendizado de maquina
3 Iterators
coisas que podem estar no =for=
for x in z:
implementam o metodo =__next__= que é chamado pela funcao =next=
que levanta a excecao =StopIteration= quando nao há proximo
try:
it = iter(z)
while True:
x = next(it)
...
except StopIteration:
pass
class meurange:
def __init__(self,baixo,alto):
self.baixo=baixo
self.alto=alto
self.i = baixo-1
def __iter__(self):
return self
def __next__(self):
if self.i<self.alto:
self.i = self.i+1
return self.i
else:
raise StopIteration
alguns iterators sao como os thunk de haskell - promessas de computacao
range(1,10) map(lambda x: x+1,[1,2,3])
mas imprimir na tela nao força a execuçao das promessas. =list=
executa as promessas e cria uma lista
range(1,20) print(range(1,20)) list(range(1,20))
4 Generators
Funcoes que guardam o estado entre uma chamada e outra e fazem o papel de um iterator
Use =yield= em vez de =return= - na proxima chamada a funçao
executa do =yield= ate o proximo =yield=
def meurange(baixo,alto):
baixo=baixo-1
while baixo< alto:
baixo = baixo+1
yield baixo
modulo itertools
5 Decorators
Funcoes que recebem uma funcao e retornam outra funçao que "envolve" aquela:
import time
def tempo(func):
def aux():
t1=time.time()
for i in range(1000):
func()
t2=time.time()
print(t2-t1)
return aux
def a():
y=[]
for x in range(10):
y.append(x)
def b():
y=[0]*10
for x in range(10):
y[x]=x
a()
a=tempo(a)
b=tempo(b)
a()
b()
decorators sao essas funcoes + syntatic sugar
@tempo
def a():
y=[]
for x in range(10):
y.append(x)
@tempo
def b():
y=[0]*10
for x in range(10):
y[x]=x
Como fazer decorators para funcoes com argumentos:
def trac(funcao):
def aux(*args):
print("inicio args:",args)
x = funcao(*args)
print("fim resultado :",x)
return x
return aux
@trac
def f(a,b,c):
return a*b-c
memorizador
def memoriza(f):
mem={}
def aux(*args):
if args in mem:
return mem[args]
else:
x = f(*args)
mem[args] = x
return x
return aux
utilizando uma classe como decorator memoizador o metodo =__call__=
é executado quando o objeto é chamado como funcao.
5.1 execicios
sem olhar o itertools implemente os generators
- zip(iter1,iter2) que retorna tuplas de iter1 e iter2
- loop(iter) => loop("abc") -> "abcabcabc…"
- produto(it1, it2) - retorna todos os pares de tuplas (a,b) onde a vem de it1 e b de it2
- esimo(k,iter) - retorna cada k-esimo elemento de iter
- prob(k,iter) - retorna cada k-esimo elemento de iter
probailisticamente - cada elemento tem uma chance de 1/k de ser
retornado - no infinito isso retorna 1/k dos elementos de iter mas
vc nao sabe dizer quais. Use a biblioteca
=random=
decorators
- decorator para contar o numero de chamadas de uma funcao. Um metodo diferente retorna o numero de chamadas e outro metodo zera a contagem
- decorator para