Aula 20

Python online

Python Tutorial

Standard library

Decorators

Forma de modificar o comportamento (externo) de classes e funções.

def llog(f):
   def wrapper(*args): 
      print("entrada:",args)
      x = f(*args)
      print("saida:",x)
      return x
   return wrapper

def aux(x,y):
   return 2*x+y

zz = llog(aux)

notação @

aux = llog(aux)

@llog
def aux(x,y):
   return 2*x+y

Decorators com estado - decorators como objetos

Voce pode retornar um objeto. se o objeto for chamado como função, o método __call__ desse objeto será executado

class decconta:
   def __init__(self,f):
      self.funcao=f
      self.conta=0
   def __call__(self,*args):
      self.conta += 1
      return self.funcao(*args)

xx=decconta(aux)

mais info

a primer on decorators

OO em python - parte 2

class e static methods https://realpython.com/instance-class-and-static-methods-demystified/ são decorators.

Exercícios

Iterator

Iterator é um thunk do haskell - uma promessa de computação que retorna um elemento por vez.

Funciona dentro de um for

classe

x = iter([2,3])
next(x)
next(x)
next(x)

for

for x in coisa:
  ...

é na verdade uma abreviação para

ii=iter(coisa)
try: 
  while True:
    x = ii.__next__()
    ...
except StopIteration:
    pass

exemplo

class Repetidor:
   def __init__(self,x,n=4):
      self.n=n
      self.x=x
   def __iter__(self):
      return self
   def __next__(self):
      if self.n<=0: 
         raise StopIteration
      else:
         self.n-=1
         return self.x

generators

Generators são funções que guardam o estado entre uma chamada e outra. Sintaticamente a unica diferença é usar um yield em vez do return

A cada execuçao, o yieldcomputa o proximo valor a ser retornado e interrompe a execuçao. No proximo next o generator continua executando do ultimo yield.

def rep(x,n=4):
  while n>0:
     n-=1
     yield x
>>> z = rep(77)
>>> z.__next__()
77
>>> next(z)
77
>>> next(z)
77
>>> next(z)
77
>>> next(z)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

generator comprehension

zz= (x*x for x in range(10,1000) if x % 4 == 0)

zz.__next__()
next(zz)

itertools

uma biblioteca para iterators https://docs.python.org/3/library/itertools.html

iterators no python

iterators no Python não sao exatamente bem conectados com o resto do python como os thunks sao em haskell (na minha opinião).

a = [6,5,3,1,7]
sorted(a)
reversed(a)
list(range(1:4))
[1,2,3] == range(1,4)

por outro lado faz algum sentido no expandir os iterators - eles vao gerando novos elementos e não dá para rewind/ voltar atras num iterator (por exemplo o iterator que le linhas de um arquivo)!

coroutines

processos que enviam mensagens de um para outro. Normalmente produtores, filtros e consumidores

um filtro precisa receber uma mensagem, e talvez enviar uma outra mensagem para o consumidor final

def filtro(padrao,proximo):
   print("Comecando filtro")
   while True:
     msg = (yield)
     if padrao in msg:
        proximo.send(msg)


def consumidor():
    print("Comecando consumidor final")
    while True:
       l=(yield)
       print(l)

c=consumidor()
f=filtro("abc",c)
c.__next__() #para chegar no yield
f.__next__() # para chegar no yield
for x in "afh ahabcj agdb yyabctt abc abdddc".split():
    f.send(x)

exercícios

Sem usar a itertools