Llistes
Les llistes (tipus de dada list) són estructures de dades essencials en Python que permeten emmagatzemar seqüències d’elements.
En aquesta lliçó s’introduirà aquest tipus de dada i s’estudiarà des del punt de vista de la connexió entre els tipus list i str, i les semblances que presenten per tractar-se de seqüències ordenades. Les str són seqüències de caràcters i les llistes són seqüències d’elements.
Ús de llistes
Explorareu els fonaments de les llistes a Python mitjançant un exemple pràctic: trobar el màxim de les parts decimals de dos nombres float llegits.
Primer programa de llistes
Enunciat del programa: trobar el màxim de les parts decimals de dos nombres float.
Especificacions d’entrada: 2 nombres float.
Joc de proves: vegeu la taula.
| Entrada | Sortida |
|---|---|
| 3., 2.100002 | [0,100002], 100002 |
| 4, 7.3 | [0,3], 3 |
| 2.02, 12.003 | [02, 003], 02 |
El codi del nou programa és el següent:
N = 2
# 1. Crear una llista amb N zeros
nombres = N * ['']
# 2.Omplir la llista
for i in range(0, N):
nombres[i] = input()
# 3. Retallar per desar només els decimals.
for i in range(0, N):
# treure decimals
original = nombres[i]
decimals = '0'
punt = original.find('.')
# si no és un natural
if not (punt == -1 or punt == len(original) -1):
decimals = original[punt + 1:]
nombres[i] = decimals
print(nombres)
# 4. Algorime del màxim
maxim = nombres[0]
for element in nombres:
if element > maxim:
maxim = element
print('maxim:', maxim)
El podeu veure amb els números de línia a la figura.
Conceptes sobre llistes que s’utilitzen en el programa:
Una llista només es pot modificar si es recorre per posició. Recorrent-la de manera natural es llegeix l’element, però no s’accedeix a la memòria per desar el canvi.
- Línia 5: es crea una llista de
strque conté 2 cadenes buides, i es desa en una variable. S’usa l’operador de llistes*. - Línies 8 i 9: s’omple la llista utilitzant el
forper recórrer-la per posició. - Línies 12 a 21: s’utilitza el
forper recórrer la llista per posició i operar amb els seus elements de tipusstr. - Línia 23: les dades de tipus llista es poden mostrar amb un
print()directament. - Línies 26 a 29: s’utilitza el
forper recórrer la llista de manera natural per aplicar l’algorisme del màxim. Fixeu-vos que s’utilitza la comparació entrestr(i no entre nombres). Per aplicar l’algorisme del màxim hauria estat millor recórrer la llista per posició i saltar-se el primer element, però s’ha fet així per mostrar que les llistes també es poden recórrer de manera natural.
Aquest és el resultat de l’execució per a l’últim cas del joc de proves:
videoioc@debian-xtec:~/Documents/programacio$ python3 part_decimal_llista.py 2.02 12.003 ['02', '003'] maxim: 02
Els valors 2.02 i 12.003 de la segona i tercera filera són les dades d’entrada.
A continuació s’introdueix el tipus de dada list i es fa un repàs de les característiques d’aquest tipus que comparteixen amb les dades str.
Tipus list
Les llistes són una estructura de dades versàtil i fonamental en Python que permet emmagatzemar una seqüència ordenada d’elements. És una manera estructurada de guardar i poder accedir a uns quants elements en conjunt, però amb la possibilitat de treballar amb cadascun d’ells de manera individual.
Una llista (o una dada de tipus list), en Python és una seqüència ordenada i mutable d’elements, que pot contenir dades heterogènies i es defineix mitjançant els parèntesis [ ].
Algunes característiques claus de les llistes són:
- Seqüència ordenada: una llista és una seqüència ordenada d’elements. Cada element té una posició o índex específic a la llista. Un altre tipus de dades que també són una seqüència ordenada i que ja coneixeu són les cadenes. Veureu que comparteixen moltes propietats.
- Elements heterogenis: les llistes poden contenir elements de diferents tipus de dades, com ara nombres, cadenes, booleans o fins i tot altres llistes. Així i tot, per poder treballar de manera ordenada i aprofitar millor les característiques de la classe, es recomana fer llistes d’un mateix tipus d’elements.
- Mutables: les llistes són mutables, el que significa que es poden modificar després de la seva creació. Podeu afegir, eliminar o modificar elements dins de la llista. Aquesta característica les diferencia del tipus de dada
strque són immutables. - Llistes d’un únic tipus d’elements: Lla manera més comuna de treballar amb llistes és definint llistes d’un únic tipus d’elements. Treballareu amb llistes de nombres (es poden combinar, o no, els tipus int i float), amb llistes de
str, amb llistes de llistes o amb llistes de qualsevol mena d’objecte.
Exemples de definició de llistes
A continuació es defineixen diverses llistes de diferents tipus d’elements:
>>> l_int = [1, 2, 3, 4] >>> l_str = ['Maria', 'Pere', 'joan manel'] >>> vocals = ['a', 'e', 'i', 'o', 'u'] >>> elements_diversos = ['', True, 'True', 0, [1, 2]] >>> llista_buida = [] >>> llista_de-llistes = [[], [0], [0, 1], [0, 1, 2]]
La llista que no conté cap element s’anomena llista buida i es representa [].
Propietats de les llistes
Veurem a continuació els aspectes més característics de les llistes. Tenir clars aquests aspectes és indispensable per saber treballar amb elles.
Longitud d'una llista
Les llistes tenen la propietat de tenir una longitud definida. La longitud d’una llista és la quantitat d’elements que la formen. Utilitzeu l’intèrpret interactiu per comprovar les instruccions següents:
>>> llista_buida = [] >>> len(llista_buida) 0 >>> vocals = ['a', 'e', 'i', 'o', 'u'] >>> len(vocals) 5 >>> llista = ['', '', ''] >>> len(llista) 3 >>> llista = ['hola'] >>> len(llista) 1 >>> llista_de_llistes = [[], [0], [0, 1], [0, 1, 2]] >>> len(llista_de_llistes) 4
La longitud de la cadena buida és zero. Poden haver-hi llistes d’un element (i de dos i dels que sigui). Fixeu-vos que en el cas d’una llista de llistes es compta la quantitat de llistes que la componen. La quantitat d’elements de cada llista interna és indiferent.
Operadors + i * per a llistes
L’operador + (concatenació), és un operador binari que pot actuar entre dues llistes. Produeix una nova llista amb els elements de la primera llista seguits pels de la segona.
L’operador * és un operador binari que actua sobre una llista i un nombre enter n. Crea una nova llista que conté la repetició n vegades dels elements de la llista inicial.
Tot seguit podeu observar un exemple de funcionament dels operadors + i * per llistes:
>>> llista1 = [2,3, 4] >>> llista2 = [5, 6] >>> llista1 + llista2 [2, 3, 4, 5, 6] >>> llista1 * 3 [2, 3, 4, 2, 3, 4, 2, 3, 4] >>> llista3 = ['hola', 'adeu'] >>> llista2 + llista3 [5, 6, 'hola', 'adeu']
L’operador + ha d’actuar entre dues dades del mateix tipus (numèriques, str o list). Per això no té cap problema en concatenar dues dades de tipus list. Fixeu-vos que no afecta que els elements d’aquestes llistes siguin de tipus diferent. Poden existir llistes amb elements de tipus heterogenis.
Indexació de llistes
La indexació de llistes funciona igual que la de les cadenes, i també accepta nombres negatius que indiquen que es comença a comptar a partir del final.
Aquest seria un exemple d’indexació de llistes:
>>> llista = [2, 3, 7, 10, 4] >>> llista[0] 2 >>> llista[3] 10 >>> llista[-1] 4 >>> llista[len(llista) - 1] 4 >>> llista[len(llista)] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range >>> llista[len(llista) -1] - 1 3
Tal com succeeix amb les cadenes, es produeix un error si s’intenta accedir amb la indexació a una posició inexistent.
Recorregut de llistes
Hi ha diverses maneres de recórrer les llistes, tal com passa amb les cadenes. Escollir-ne una o altra dependrà de l’objectiu del programa.
Recórrer de manera natural
Quan una llista s’itera element a element es diu que es recorre de manera natural. Executeu aquest programa i comproveu-ne el resultat.
llista = [2, 3, -3, 5] for element in llista: print(element)
Quan es recorre de manera natural, la variable element és del mateix tipus que l’element que li toca de la llista. En aquest cas, es tracta d’una llista d’enters i element és un enter. Si la llista fos de cadenes, element seria un str. Si la llista és d’elements de diferents tipus, la variable també ho serà a cada passada.
Recórrer per posició
Si necessiteu la posició que ocupa un element, el millor és recórrer la llista ajudant-vos de l’objecte range (tal com es fa amb les cadenes). Executeu el següent exemple:
llista = [2, 3, -3, 5] for pos in range(0, len(llista)): print(llista[pos], pos)
Comprovareu que es relaciona l’element amb la posició que ocupa. En aquest cas, el tipus de la variable pos serà sempre un enter, independentment dels tipus de l’element de la llista.
Recórrer sense arribar al final
Recordeu que si en un bucle es vol sortir abans d’acabar la seqüència, quan es doni una certa condició, el bucle adequat serà el while. Si feu servir el for s’iterarà per tots els elements de la llista o del range().
En aquest exemple s’acabarà el recorregut en arribar al penúltim element de la llista.
llista = [2, 5, 12, 45, 23] pos = 0 while pos < len(llista) - 1: print(llista[pos]) pos += 1
Comparar llistes
Comparar llistes amb operadors relacionals o de comparació és una pràctica comuna en Python. La manera d’aplicar els operadors == i != és intuïtiva: dues llistes són iguals només si tenen la mateixa longitud i tenen els mateixos elements en cada posició. Com sempre amb aquests dos operadors, es poden comparar una llista i qualsevol altre tipus de dada. Només seran iguals en el cas que s’acaba d’esmentar.
Dues llistes només es poden comparar amb els operadors >, <, >= i ⇐ si cada element d’una es pot comparar amb l’element que està en la mateixa posició de l’altra.
Els operadors >, <, >= i ⇐ també s’utilitzen en comparacions entre llistes, seguint un ordre lexicogràfic similar al que s’utilitza amb cadenes. Per exemple, quan es compara llista1 amb llista2, es pren el primer element de cada llista i es comparen. Si un és major que l’altre, la llista amb l’element major és considerada major. En cas que siguin iguals, es passa al segon element i així successivament fins que s’acaben les llistes o es troba un element diferent.
Cal destacar que dues llistes són comparables només si els seus elements també ho són. La comparació entre llistes no sempre es pot dur a terme (al contrari del que succeeix amb les cadenes). Fixeu-vos en les comparacions següents i assegureu-vos que enteneu el perquè del resultat:
>>> [1, 2] < [1, 2] False >>> [1, 2, 3] <= [1, 2] False >>> [2] < [1, 2, 3] False >>> [1, 2, 3] <= ['hola', 'adeu'] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: '<=' not supported between instances of 'int' and 'str' >>> ['abc', 'abc'] < ['abecedari'] True >>> ['1', '2', '3'] < ['1', '2', '2'] False >>> [1, 'hola'] <= [1, 'adeu'] False >>> ['1', '2'] < ['1', '12'] False
La comparació entre llistes es basa en la comparació entre els seus elements. Segons el tipus de cada element s’utilitza l’operador de comparació adequat. En l’últim exemple, en la comparació entre str “12” és menor que “2”, el que implica que la segona llista és menor que la primera.
Slicing llistes
La tècnica de slicing (que podem traduir com retallar) és una poderosa eina que permet extreure subseqüències específiques d’una llista. Aquesta operació es realitza de manera similar al slicing de cadenes, proporcionant flexibilitat en la manipulació de dades en Python.
Comproveu els següents exemples per entendre millor com funciona:
>>> llista = [2, 3, -3, 5, 2, 0] >>> llista[:3] [2, 3, -3] >>> llista[2:] [-3, 5, 2, 0] >>> llista[1:2] [3] >>> llista[-1:] [0] >>> llista[:-1] [2, 3, -3, 5, 2] >>> llista[10:15] []
Podeu comprovar que, tal com passava amb el cas de les cadenes, el slicing no produeix errors si troba índexs inexistents, sinó que retorna la cadena buida.
Pertinència d’un element a una llista
Els operadors in i not in són operadors binaris que poden ser aplicats a molts tipus de dades seqüencials o estructures de dades en Python. En general, aquests operadors comproven si un element és present dins d’una seqüència o eina de dades específica.
En concret, també es pot aplicar sobre les llistes. Comproveu la resposta amb l’intèrpret interactiu en aquests casos:
>>> llista = ['hola', 'adeu'] >>> 'hola' in llista True >>> 'holi' not in llista True >>> 'o' in ['hola'] False >>> 'la' in llista[0] True
Fixeu-vos que en l’últim exemple l’operador in actua sobre cadenes.
Conceptes clau sobre llistes
Ara ja coneixeu la classe list i heu vist les característiques que comparteixen les dades de tipus list amb les de tipus str. A continuació teniu una síntesi dels conceptes clau, perquè els tingueu de referència.
Una dada de tipus list és una seqüència ordenada i mutable d’elements, que pot contenir dades heterogènies i es defineix mitjançant els parèntesis [].
Conceptes més importants, que són idèntics als de les cadenes però substituint els caràcters de la cadena per als elements de la llista:
- Una llista es defineix:
llista = [element0, element1, ...]
- La llista buida és:
llista_buida = []
- La longitud d’una llista és la quantitat d’elements que té.
- Es poden utilitzar els operadors binaris concatenació
+i repetició*per ajuntar dues llistes o per repetir una llista una certa quantitat de vegades. - Es pot accedir a un element d’una llista a través de la seva posició mitjançant la indexació.
llista[0]
- Hi ha 3 maneres diferents de recórrer una llista:
- De manera natural:
for element in llista: instruccions
- Per posició:
for pos in range(len(llista): instruccions
- Amb un
whilepos = 0 while condicio: instruccions pos += 1
- Els operadors de comparació es poden utilitzar entre les llistes si els seus elements són comparables per cada posició. L’ordre definit per a la comparació és semblant al lexicogràfic entre els seus elements. La comparació entre els elements de dues llistes és la que tinguin definida el tipus dels elements.
- Es poden formar subllistes amb l’operador de slicing.
llista[3:10]
- Es pot utilitzar l’operador
inper comprovar si una subllista pertany o no a una llista.
Lectura de dades per la línia d'ordres
Fins a aquest moment, l’entrada de dades en els vostres programes s’ha produït mitjançant la funció input() que llegeix les dades de stdin. En general, les dades no s’introdueixen per teclat sinó que es redirigeix un fitxer a l’entrada estàndard.
En aquesta secció aprendreu a entrar les dades per la línia d’ordres (també es diu pas per argument), tal com fan les utilitats de Linux, i a distingir quan és millor per al vostre programa que entrin per argument o per stdin.
Per començar, fixeu-vos com actuen les següents comandes de Linux:
Exemple d'entrada de dades per la línia d'ordres
La comanda head pot rebre dos arguments: el nombre de línies i el fitxer a mostrar. En aquest exemple el fitxer és el programa de la figura.
videoioc@debian-xtec:~/Documents/programacio$ head -3 pas_per_argument.py import sys MISSATGE = 'Usage: programa.py nombre_enter'Els dos arguments que han acompanyat al nom de l’ordre
head en la crida des de la línia d’ordres són les dades d’entrada del programa. En aquesta ocasió el programa head s’espavilarà per a accedir a les dades del fitxer.
L’ordre head (de sistema) mostra les primeres línies d’un fitxer. Es pot descuidar d’un argument que indica la quantitat de línies a mostrar, i el fitxer li pot passar per argument, o redirigint l’entrada estàndard.
Exemple d'entrada mixta: per línia d'ordres i per stdin
També es poden combinar els dos mètodes d’entrada: en aquest cas la comanda head rep la quantitat de línies a mostrar per la línia d’ordres i, en canvi, el fitxer és llegit per l’entrada stdin:
videoioc@debian-xtec:~/Documents/programacio$ head -1 < pas_per_argument.py import sys
Exemple de dades incorrectes
Si les entrades no són vàlides (no respecten les especificacions d’entrada), el programa dona un missatge d’error en el qual es dona informació sobre com s’utilitza i interromp l’execució.
videoioc@debian-xtec:~/Documents/programacio$ grep Usage: grep [OPTION]... PATTERNS [FILE]... Try 'grep --help' for more information.La comanda
grep de Linux no es pot executar sense cap argument.
L’ordre grep, de Linux, serveix per buscar línies que continguin un patró. No pot utilitzar-se sense passar-li el patró com a argument.
La política de control d’errors dels programes d’aquest curs de programació, en la gran majoria de casos, seguirà l’exemple d’aquestes comandes de Linux.
Primer programa amb entrada de dades per la línia d'ordres
Per a introduir el pas per argument seguirem pas a pas un programa que llegeix un valor de la línia d’ordres i opera amb ell.
En concret, el programa llegeix un nombre enter i el multiplica per -0.5. El programa ha de ser robust, i si la dada introduïda no és bona, finalitzar l’execució amb un missatge d’error. Les especificacions d’entrada són: un nombre enter. I el joc de proves el teniu detallat a la taula.
| Entrada | Sortida |
|---|---|
| 4 | -2.0 |
| 0 | 0.0 |
| -1 | 0.5 |
A més, com que es vol que sigui robust, teniu també definit el comportament del programa quan l’entrada sigui errònia. Es concreta al joc de proves del control d’errors que podeu veure a la taula.
| Entrada | És acceptada? |
|---|---|
| -1 | True |
| 1. | False |
| +23 | True |
| patata | False |
| 2-3 | False |
| +-2 | False |
El codi del programa és el següent:
import sys MISSATGE = 'Usage: programa.py nombre_enter' VALOR = -0.5 print(sys.argv) # CONTROL D'ERRORS # El primer pas és comprovar que existeixi l'argument if len(sys.argv) <= 1: print(MISSATGE) exit(1) # Ara es pot accedir al primer argument primer_argument = sys.argv[1] # Comprovar que és enter if primer_argument[0] in '+-': primer_argument = primer_argument[1:] if not primer_argument.isdigit(): print(MISSATGE) exit(1) # PROGRAMA PRINCIPAL # Convertir a enter sense problemes. (primer_argument no té sense signe) num = int(sys.argv[1]) print(num * VALOR)
En la figura es presenta el programa complet amb els números de línia.
Conceptes nous sobre la lectura de dades per la línia d’ordres:
- Línia 1: cal importar el mòdul
sysperquè el programa necessitarà accedir a la llistasys.argv, definida en aquest mòdul. - Línia 6: es mostra la llista
sys.argvque es crea en temps d’execució. - Línies 10 a 12: la llista
sys.argvconté el nom del programa i els arguments amb els quals s’ha cridat per la línia d’ordres. El primer que ha de fer el control d’errors és evitar que es produeixi un error si s’accedeix a una posició inexistent utilitzant la indexació de llistes. - Línia 15: es pot accedir de forma segura a la posició 1 de la llista
sys.argv, que és on hi ha el primer argument. - Línia 27: s’han fet les comprovacions oportunes per poder convertir el primer argument a enter. En aquest cas no es fa servir la variable
primer_argumentperquè hi ha la possibilitat que se li hagi retallat el signe.
Per a entendre què és sys.argv, fixeu-vos en les següents execucions del programa segons els arguments que li passen per alt per la línia d’ordres:
Diferents execucions del programa
videoioc@debian-xtec:~/Documents/programacio$ python3 pas_per_argument.py 4 ['pas_per_argument.py', '4'] -2.0
videoioc@debian-xtec:~/Documents/programacio$ python3 pas_per_argument.py ['pas_per_argument.py'] Usage: programa.py nombre_enter
videoioc@debian-xtec:~/Documents/programacio$ python3 pas_per_argument.py -e patata aeiou ['pas_per_argument.py', '-e', 'patata', 'aeiou'] Usage: programa.py nombre_enter
videoioc@debian-xtec:~/Documents/programacio$ python3 pas_per_argument.py -23 'R2D2 C3P0' ['pas_per_argument.py', '-23', 'R2D2 C3P0'] 11.5
En l’última execució es mostren dues coses:
- Es sol permetre l’execució del programa principal tot i que hi hagi més arguments dels necessaris. Les dades que no s’utilitzen no molesten.
- Si es vol que un argument tingui un espai en blanc, s’han de posar les cometes simples o dobles per unir dues paraules. En cas contrari, cada espai indica una nova posició en la llista d’arguments.
La llista sys.argv
sys.argv és una llista de cadenes que emmagatzema els arguments passats a un programa o script Python quan aquest és executat des de la línia d’ordres. S’actualitza dinàmicament en temps d’execució.
El mòdul sys proporciona accés a algunes variables relacionades amb l’entorn del sistema.
Les característiques principals de sys.argv que heu de tenir en compte en programar són:
sys.argvés una variable que està definida en el mòdulsys. Per això cal importar-lo si es vol utilitzar la llista d’arguments.- És una llista de
str. Això indica que les dades llegides per la línia d’ordres entren sempre com a cadenes i s’han de manipular si el tipus de dada requerit és un altre. Tal com passa amb la lectura per l’entrada estàndard. Si es necessita treballar amb un enter, un float o qualsevol altre tipus de dada el programa ha de fer la conversió. - La primera posició (
sys.argv[0]) l’ocupa el nom del programa. No és més que una cadena que s’anomena com el fitxer on està escrit el codi que s’està executant. - Les posicions restants les ocupen el primer argument, el segon, etc. Cada espai en blanc de la línia d’ordres separa un argument.
Llegir dades per stdin o per la línia d'ordres
Escollir un mètode d’entrada de dades dependrà del tipus de dades d’entrada que necessiti el programa i del propòsit d’aquest. A continuació teniu algunes reflexions que us ajudaran a triar un mecanisme o l’altre de lectura.
De moment sabeu llegir les dades per stdin i per la línia d’ordres. Més endavant aprendreu a manipular i llegir fitxers des d’un programa.
En els següents casos és preferible llegir dades per la línia d’ordres:
- Pocs paràmetres o valors simples: és convenient utilitzar la línia d’ordres quan el programa requereix pocs paràmetres o valors simples, com nombres o llistes curtes. Això ofereix simplicitat i facilitat en l’execució.
- Paràmetres i opcions configurables: la línia d’ordres és preferible quan necessiteu que els scripts siguin configurables i acceptin diversos paràmetres i opcions.
- Automatització de tasques: és útil en scripts destinats a l’automatització de tasques, ja que permet la integració senzilla amb altres eines i scripts.
- Scripts de sistema o administració: és adequat per a scripts d’administració de sistema que interactuen amb comandes específiques del sistema operatiu.
Però en aquestes altres casuístiques, serà preferible llegir dades per stdin:
- Entrada de dades extenses: si el programa requereix la introducció de moltes dades o molt extenses (com treballar amb textos) és més pràctic llegir-les per
stdini redirigir un fitxer de text. - Interacció amb l’usuari en temps real:
stdinés adequada quan la interacció amb l’usuari és necessària en temps real, amb dades que es proporcionen de manera incremental. - Programes interactius: si es requereix que l’usuari entri les dades directament segons les decisions que pren durant l’execució del programa, s’hauran de llegir les dades per
stdin. - Flexibilitat amb redirecció de fitxers: llegir per
stdinpermet als usuaris redirigir fàcilment l’entrada mitjançant operadors de redirecció, com>o<, facilitant la integració amb altres processos i fitxers.
Conceptes clau sobre la lectura per la línia d'ordres
En síntesi, els aspectes més importants que heu de tenir en compte quan heu de fer programes que llegeixin de línia d’ordres, són els següents:
- La lectura de les dades per la línia d’ordres es fa, essencialment, utilitzant la llista d’arguments
sys.argvdel mòdulsys. - Per utilitzar-la cal importar el mòdul
sys. sys.argvés una llista destr, on l’element que ocupa la posició 0 és el nom del fitxer del programa que s’està executant, i els altres elements són els arguments que passen per la línia d’ordres quan s’invoca el programa.- En la majoria dels scripts i programes del sistema o d’administració, és la manera idònia d’introduir les dades.
- Fins que no aprengueu a manipular fitxers, quan es requereixin dades desades en un fitxer s’hauran de llegir redirigint el fitxer a
stdin. Això no impedeix que altres paràmetres s’introdueixin per la línia d’ordres.





