Iteradores em Python

Durante o curso discutimos um pouco sobre implementação dos chamados ‘métodos mágicos’ de python. Ao invés de interfaces, python adota protocolos a serem seguidos para que objetos criados por você programador obedeça alguns comportamentos, e é por ai que python implementa polimorfismo.

Vejamos por exemplo a função len():

>>> string = ‘flavio’
>>> len(string)
6
>>> lista = ['flavio',21,'ifpb']
>>> len(lista)
3

Ela tem a capacidade de retornar o tamanho de um objeto, mas não de qualquer objeto:

>>> a = 3
>>> len(a)
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
TypeError: object of type ‘int’ has no len()

Se você quiser que seu próprio objeto consiga retornar o tamanho ou comprimento de algo pela função len() basta você escrever o método mágico __len__ na sua classe. Imagine que você tem uma classe Pessoa e quer saber a altura das pessoas através do len():

>>> class Pessoa(object):
…     def __init__(self, altura=0):
…             self.altura = altura
…     def __len__(self):
…             return self.altura

>>> Flavio = Pessoa(184)
>>> len(Flavio)
184

Legal, né? Agora, pra não fugir muito o escopo desse post, vamos aos iteradores. Um iterador é basicamente um objeto que pode ser incrementado e decrementado, ser ‘percorrido’. A palavra iterar significa repetir algo algumas vezes. No  python 3 uma função muito utilizada nos laços for, a range(), que antes retornava uma lista (que por sua vez é iteravel) nas versões 2.x agora se comporta como a antiga xrange(), retornando um objeto em si que tem a capacidade de iterar.

No Python 2.X:

>>> type(xrange(3))
<type ‘xrange’>
>>> type(range(3))
<type ‘list’>

No Python 3000 (Py3k, Python 3):

>>> type(range(10))
<class ‘range’>
>>> xrange(10)
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
NameError: name ‘xrange’ is not defined

Sabendo já sobre métodos mágicos e o que são iteradores chegou a hora de criar um iterador mesmo, na real. Para você ter um iterador, basta que você crie um método mágico chamado __iter__() retornando a própria instância e um outro método chamado next(), onde as coisas vão realmente acontecer a cada iteração.

Como sou péssimo com exemplos vou simplificar e criar apenas uma classe que gera a velha conhecida dos programadores, ou pelo menos das pessoas que pagaram introdução aos algoritmos: Fibonacci.

  1.  
  2. class Fibonacci(object):
  3. def __init__(self):
  4. self.a = 0
  5. self.b = 1
  6. def __iter__(self):
  7. return self
  8. def next(self):
  9. self.a, self.b = self.b, self.a+self.b
  10. return self.a
  11.  

Pronto, agora podemos iterar em cima do nosso proprio objeto!

>>> fib = Fibonacci()
>>> for num in fib:
…     if num < 150:
…             print num,
…     else:
…             break

1 1 2 3 5 8 13 21 34 55 89 144

Sim, e esse plugin de colorir sintaxe já tá me irritando, engoliu a identação, quebras de linha e etc. Quem usar algum plugin melhor favor me avisar nos comentários!

2 Responses

  1. Igor Sobreira Says:

    Fala Flávio!

    Só tenho uma observação a fazer, na class Fibonacci, sendo um objeto iterável, eu acho que ele deveria ter sua condição de parada no método .next().

    Eu implementaria dessa maneira:

    class Fibonacci(object):
    def __init__(self, limit):
    self.limit = limit
    self.a = 0
    self.b = 1

    def __iter__(self):
    return self

    def next(self):
    self.a, self.b = self.b, self.a + self.b
    if self.a >= self.limit:
    raise StopIteration
    return self.a

    >>> f2 = Fibonacci(150)
    >>> for n in f2: print n,

    1 1 2 3 5 8 13 21 34 55 89 144

    Botei aqui no dpaste, caso fique ruim de ler aqui nos comentários:
    http://dpaste.com/hold/14412/

    Parabéns pelos post. O blog tá bem interessante ultimamente :)

  2. Flávio Ribeiro Says:

    Fala Igor,

    Brigado pelo elogio do blog, tenho mais algumas idéias para novos posts e espero que continue a achar interessante.

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.