Iterables i iteradors¶
Què vol dir iterar?¶
Iterar és repetir una acció més d’una vegades.
La sentència
for
permet iterar.>>> a = [5, -2, 3] >>> s = 0 >>> for e in a: # capçalera ... if e > 0: # cos ... s = s + e # cos
La sentència
while
permet iterar.>>> m = 100 >>> i = 0 >>> while 2**i < m: # capçalera ... i = i + 1 # cos
L’acció que es repeteix quan iterem amb una sentència
for
owhile
és el cos de la sentència.
Què és un objecte iterable?¶
Un objecte és iterable si podem recórrer els seus elements un rere l’altre en una sentència
for
.
Les llistes són iterables:
>>> llista = [1, 2, 3] >>> p = 1 >>> for element in llista: ... p = p * element >>> p 6
Els tuples són iterables:
>>> tuple = (1, 2, 3) >>> p = 1 >>> for element in tuple: ... p = p * element >>> p 6
Els diccionaris són iterables:
>>> dicc = {'un':1, 'dos':2, 'tres': 3} >>> p = 1 >>> for clau in dicc: ... p = p * dicc[clau] >>> p 6
Els strings són iterables:
>>> cadena = "123" >>> p = 1 >>> for car in cadena: ... p = p * int(car) >>> p 6
Els fitxers són iterables:
>>> p = 1 >>> with open('nom_fitxer.txt', 'r') as f: ... for linia in f: ... p = p * int(linia) >>> p 6
Els enters no són iterables:
>>> enter = 123 >>> p = 1 >>> for digit in enter: ... p = p * digit Traceback (most recent call last): File "/usr/lib/python3.5/doctest.py", line 1321, in __run compileflags, 1), test.globs) File "<doctest iterables.txt[24]>", line 1, in <module> for digit in enter: TypeError: 'int' object is not iterable
Què és un objecte iterador?¶
Un objecte és iterador si és iterable, però només podem recórrer el seus elements un sol cop.
Els objectes iteradors s’esgoten: no es poden tornar a recórrer.
>>> with open('nom_fitxer.txt', 'r') as f: ... print('Primer recorregut') ... for linia in f: ... print(linia, end='') ... print('\nSegon recorregut') ... for linia in f: ... print(linia, end='') Primer recorregut 1 2 3 Segon recorregut
Per tant, podem classificar els objectes iterables com:
- Contenidors iterables
objectes contenidors que es poden recórrer múltiples vegades. Per exemple, strings, llistes, tuples o diccionaris.
- Iteradors
objectes que només es poden recórrer un cop. Per exemple, els fitxers (file object).
Com funciona la sentència for?¶
L’intèrpret de Python executa el for
>>> llista = [1, 2]
>>> for element in llista:
... print(element)
1
2
com segueix:
Crida la funció
iter()
sobre l’objecte iterable per tal d’obtenir un iterador:>>> it = iter(llista)
Obté l’element de la primera iteració cridant la funció
next()
sobre l’iterador:>>> element = next(it)
Executa el cos del
for
>>> print(element) 1
Obté l’element de la segona iteració cridant la funció
next()
sobre l’iterador:>>> element = next(it)
Executa el cos del
for
>>> print(element) 2
Intenta obtenir l’element de la tercera iteració cridant la funció
next()
sobre l’iterador, però es produeix l’excepcióStopIteration
perquè l’iterable no té més elements:>>> element = next(it) Traceback (most recent call last): File "/usr/lib/python3.5/doctest.py", line 1321, in __run compileflags, 1), test.globs) File "<doctest iterables.rst[31]>", line 1, in <module> element = next(it) StopIteration
En detectar l’excepció
StopIteration
, acaba l’execució de la sentènciafor
i continua per la sentència següent.
Què caracteritza un objecte iterable?¶
Té mètode
__iter__()
.>>> o = [1, 2, 3] >>> hasattr(o, '__iter__') # les llister són iterables True >>> o = 3 >>> hasattr(o, '__iter__') # els enters no False
Pot ser argument de la funció
iter()
.>>> o = [1, 2, 3] >>> it = iter(o) # les llister són iterables >>> o = 3 >>> it = iter(o) # els enters no Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'int' object is not iterable
Es pot recórrer amb un
for
.>>> o = [1, 2, 3] >>> for e in o: ... print(e) ... 1 2 3 >>> o = 3 >>> for e in o: ... print(e) ... Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'int' object is not iterable
Què caracteritza un objecte iterador?¶
Té mètode
__next__()
.>>> o = iter([1, 2, 3]) # iter retorna un iterador >>> hasattr(o, '__next__') True >>> o = [1, 2, 3] >>> hasattr(o, '__next__') False
Pot ser argument de la funció
next()
.>>> o = iter([1, 2, 3]) >>> e = next(o) >>> e 1 >>> o = [1, 2, 3] >>> e = next(o) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'list' object is not an iterator
Es pot recórrer amb un
for
només un cop.>>> o = iter([1, 2, 3]) >>> for e in o: ... print(e) ... 1 2 3 >>> for e in o: ... print(e) ... >>>
El mètode
__iter__()
d’un objecte iterador retorna el mateix objecte.>>> o = iter([1, 2, 3]) >>> o is iter(o) True
Objectius¶
Volem definir objectes iteradors de forma senzilla (Funcions generadores).
Volem incorporar noves estratègies per resoldre problemes (Combinació d’iteradors).
Volem que els objectes de les classes contenidores definides pels programadors puguin ser iterables (Contenidors iterables).