Com funciona Python per sota: objectes i referències
Python no té apuntadors com C, però el mecanisme de sota és semblant: una variable no és una capsa amb un valor a dins, és un nom que apunta a un objecte. El que canvia és si aquell objecte es pot modificar un cop creat.
Dos comportaments diferents
Els tipus immutables (int, float, str, bool, les tuples) no es poden canviar un cop creats: quan "els reassignes" dins d'una funció, en realitat crees un objecte nou i hi apuntes el nom local — per això incrementa(n) (del capítol de funcions) mai tocava la variable original.
Els tipus mutables (les llistes) sí que es poden modificar sense crear-ne cap altre: llista.append(x) o llista[0] = 9 canvien l'objecte mateix. Com que la funció rep una referència al mateix objecte que té el cridant, aquests canvis sí que es veuen des de fora.
Llistes com a paràmetre: per fi, canvis que persisteixen
Exemple
def incrementa_tots(llista):
for i in range(len(llista)):
llista[i] = llista[i] + 1
valors = [1, 2, 3]
incrementa_tots(valors)
print(valors)
La sortida és [2, 3, 4]: a diferència de l'exemple amb un int del capítol de funcions, aquí sí que es veu el canvi des de fora. La funció no té una còpia de la llista; té el mateix objecte que valors, només que amb un altre nom (llista) a dins.
Retorn múltiple amb tuples
A C, una funció només pot fer return d'un sol valor (per retornar-ne més calen apuntadors, com fa scanf). Python ho resol de forma molt més directa: empaquetant diverses dades en una tupla.
Exemple
def dividir(a, b):
return a // b, a % b
quocient, residu = dividir(17, 5)
print(f"{quocient} i {residu}")
return a // b, a % b crea i retorna la tupla (3, 2) en una sola instrucció. Qui crida la funció la pot desempaquetar directament en dues variables, quocient i residu, igual que ja vam fer amb tuples "soltes" al capítol de funcions.
Ordenació: el mètode de la bombolla
Amb llistes com a paràmetre, ja podem escriure una funció que ordeni una llista de debò, modificant-la des de dins — el mateix algorisme que a C.
Exemple
def bombolla(llista):
n = len(llista)
for i in range(n - 1):
for j in range(n - 1 - i):
if llista[j] > llista[j + 1]:
llista[j], llista[j + 1] = llista[j + 1], llista[j]
La idea és idèntica a la de C: recórrer la llista comparant parelles consecutives i intercanviar-les si estan desordenades, repetint prou voltes perquè els valors més grans "pugin" cap al final. L'únic que canvia és l'intercanvi: en lloc d'una variable temp, Python el fa en una sola línia amb assignació múltiple — llista[j], llista[j + 1] = llista[j + 1], llista[j].
Bonus: sorted() i .sort()
A la pràctica, rarament escriuràs la teva pròpia ordenació: Python ja en porta. sorted(llista) retorna una llista nova, ordenada, sense tocar l'original; llista.sort() l'ordena in place, mutant-la directament — exactament el mateix mecanisme que acabem de veure amb bombolla.
Mira el programa executar-se pas a pas
Fixa't en com la llista del panell "Llista" va canviant quan la funció hi escriu — la prova que no treballa amb cap còpia.
Referències i retorn múltiple
Llistes i funcions
Codi
Variables
| Nom | Valor |
|---|
Llista
Terminal
Problemes per resoldre
Sense solució ni comprovació automàtica: escriu el programa, executa'l (python3 programa.py) i prova'l amb els exemples. Les pistes són plegades perquè les obris només si les necessites.
1. Mínim i màxim alhora
Escriu una funció min_max(llista) que retorni, en una sola tupla, el valor mínim i el màxim de la llista. Prova-la amb una llista d'uns quants enters escrits directament al codi.
Mínim: 2, Màxim: 9
Pistes
Comença suposant que tots dos són llista[0], i recorre la resta comparant cada element amb els dos candidats actuals.
return minim, maxim — i, en cridar-la: mn, mx = min_max(valors).
2. Doblar una llista
Escriu una funció dobla(llista) que multipliqui per 2 cada element de la llista, modificant-la directament (sense fer return ni crear-ne cap altra).
Abans: [1, 2, 3] Després: [2, 4, 6]
Pistes
Recorre els índexs amb for i in range(len(llista)): i reassigna llista[i] = llista[i] * 2 — igual que incrementa_tots de la teoria.
3. Ordenació per selecció
Escriu una funció seleccio(llista) que ordeni la llista amb un algorisme diferent de la bombolla: a cada passada, busca l'element més petit de la part encara no ordenada i l'intercanvia amb el primer d'aquesta part.
Abans: [5, 2, 4, 1] Després: [1, 2, 4, 5]
Pistes
Bucle de fora i de 0 a len(llista)-2: a cada volta, busca l'índex del mínim entre llista[i] i l'últim element (un bucle de dins que guarda l'índex, no el valor).
Un cop trobat l'índex del mínim, intercanvia'l amb llista[i] amb assignació múltiple: llista[i], llista[idx_min] = llista[idx_min], llista[i].
4. Invertir una llista
Escriu una funció invertir(llista) que giri l'ordre dels elements (el primer passa a ser l'últim, i així), modificant-la directament — sense fer servir reverse() ni cap llesca com [::-1].
Abans: [1, 2, 4, 5] Després: [5, 4, 2, 1]
Pistes
Amb dos índexs esquerra (comença a 0) i dreta (comença a len(llista) - 1) que s'acosten: intercanvia llista[esquerra] amb llista[dreta] i avança'ls fins que esquerra >= dreta.
L'intercanvi, com sempre en Python: llista[esquerra], llista[dreta] = llista[dreta], llista[esquerra].
Exercicis d'autoavaluació
Aquests es generen amb valors nous a l'atzar i tenen solució comprovable.
Quina serà la sortida per terminal d'aquest programa?