Aula 19
1 Iterator
Iterator é um thunk do haskell - uma promessa de computação que retorna um elemento por vez.
1.1 classe
- tem que ter um metodo
__iter__
que retorna um interator. A funçaoiter
chama o metodo__iter__
- tem que ter o metodo
__next__
que retorna o proximo elemento. A funçãonext
chama o metodo__next__
- gera a exception
StopIteration
quando não há mais elementos
x = iter([2,3]) next(x) next(x) next(x)
for x in l: ... ii=iter(l) try: while True: x = ii.__next__() ... except StopIteration: pass
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
1.2 generators
Generators são funcoes que guardam o estado entre uma chamada e
outra. Sintaticamente a unica diferença é usar um yield
em vez do
return
def rep(x,n=4): while n>0: n-=1 yield x
1.3 generator comprehension
- Como list comprehention, mas usando
(
4)
zz= (x*x for x in range(10,1000) if x % 4 == 0) zz.__next__() next(zz)
1.4 intertools
uma biblioteca para iterators https://docs.python.org/3/library/itertools.html
1.5 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
- enviar mensagem
consumidor.send(msg)
- receber mensagem
msg = (yield)
def filtro(padrao,proximo): print("Comecando filtro") while True: msg = (yield) if padrao in msg: proximo.send(msg) def consumidor(): print("Comecando consumidor") 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)
2 exercicios
Sem usar a itertools
- pares: dado um iterator, retorna um iterator com os elementos nas posicoes pares (0,2,..)
- reverte: dado um iterator, reverte ele *
- zip: dado 2 iterators, retorna um iterator que retorna os elementos intercalados
- cart: dado 2 iterators, retorna um iterator com o produto cartesiano dos elementos *
- ciclo: dado um iterator, retorna os elementos num ciclo infinito
- rangeinf(init,passo=1): retorna um iterator que gera numeros de init ate infinito, com passo
- take: como o take do haskell
- drop - como o drop do haskell
3 OO in Python
3.1 class
class Pessoa: def setidade(self,x): if x >0 : self.idade=x def getidade(self): return self.idade
So da para definir os metodos. (Normalmente) nao ha a definicao de atributos/campos/variavies
Há sempre o parametro self
para os metodos, que indicam o objeto
sobre o qual o metodo esta sendo executado
3.2 objetos
Atribuos/campos/variaveis dos objetos são sempre visiveis e modificaveis!! Nao ha atributos privados
x=Pessoa() x.setidade(12) x.getidade() x.idade x.idade=99 x.nome="jose"
Usualmente indica-se um atributo privado usando dois underscores __nome__
3.3 Construtor
Pessoa()
cria um objeto, se existe isso chama o construtor
__init__
class Pessoa: def __init__(self,idade,nome): if idade>0: self.idade=idade self.nome=nome x = Pessoa(-45,"jose")
3.4 Herança
class Aluno(Pessoa): pass a=Aluno() isinstance(a,Aluno) isinstance(a,Pessoa)
3.5 atributos de classe
class Pessoa: npernas=2 x=Pessoa() y=Pessoa() x.npernas x.npernas=9 x.npernas y.npernas Pessoa.npernas Pessoa.npernas=10 y.npernas x.npernas
3.6 OO in python?
Usualmente nao se cria um monte de objetos.
Usualmente objetos sao uma interface para as bibliotecas
3.7 Python object model
https://docs.python.org/3/reference/datamodel.html
operator overloading; definir diferentes acoes para o mesmo operador
x[i] acesso em listas e dicionários
- x[i] na verdade chama o metodo
__getitem__(x,i)
__str__
é chamado pelo print para imprimir um dado (converte p/ string)__init__
e__new__
sao chamados pelo construtor__eq__(x,y)
é chamado na comparacao x == y__getattr__(self, name)
chamado emx.a
__setattr__
para setar um atributo__call__(self[, args...])
chamado emx(a,b,c)
__len__(self)
para len__iter__(self)
e__next__(self)
ja vimos__add__
para +