--- title: ASIX M3. [UF2]. Abast i mutabilitat. tags: asix, programació, funcions, programació modular --- # ASIX1 M03: Programació bàsica [vincle a font en MarkDown](https://hackmd.io/@JdaXaviQ/ryXvu18Zq) --- # Abast i mutabilitat (scope) ## Abast Quan treballem amb funcions no totes les variables es poden veure des de qualsevol part del programa. Al troç de programa on una variable és visible li diem '__abast__'. Per exemple: Una funció que definim dins d'una funció no la podem veure des de fora: ```python def la_meva_funcio(): variable_interna = 5; print(f"Dins de la funció: {variable_interna = }") la_meva_funcio() print(f"Fora de la funció: {variable_interna = }") ``` Dins de la funció: variable_interna = 5 --------------------------------------------------------------------------- NameError Traceback (most recent call last) Input In [1], in <module> 3 print(f"Dins de la funció: {variable_interna = }") 5 la_meva_funcio() ----> 6 print(f"Fora de la funció: {variable_interna = }") NameError: name 'variable_interna' is not defined Però dins de les funcions _si_ que podem veure les variables que s'han definit a fora: ```python variable_externa = 5 def suma_interna_externa(): variable_interna = 3 print (f"{variable_interna + variable_externa = }") suma_interna_externa() ``` ## Mutabilitat Segurament que hem sentit alguna vegada que Python és un programa orientat a objectes. Nosaltres de moment no sabem què és un objecte, però per a Python internament tots els tipus de dades són objectes i això vol dir que totes les variables tenen algunes coses en comú; per exemple a Python, totes les dades tenen una __identitat__, un __tipus__ i un __valor__. Podem veure un exemple amb una variable de tipus __str__ i una altra de tipus __int__: ```python def mutabilitat(): text = "foo, bar" quantitat = 6 print(f"{id(text) = }") print(f"{type(text) = }") print(f"{text = }") print("--- --- ---") print(f"{id(quantitat) = }") print(f"{type(quantitat) = }") print(f"{quantitat = }") mutabilitat() ``` Ara que coneixem que les dades a Python tenen tipus encara que no els hi diguem explícitament, hem de saber que alguns tipus de dades a Python són mutables i d'altres son inmutables i que això té implicacions a l'hora de passar les dades com a paràmetres a les nostres funcions o com a mínim a l'hora de tornar a utilitzar aquestes dades desprès d'haver passat per alguna funció. ### Alguns tipus de dades inmutables * Booleans * Tuples * Enters * Decimals de coma flotant * Bytes * Range * Cadenes de text ### Alguns tipus de dades mutables * Llistes * Diccionaris * Sets Al següent exemple podem observar que si intentem modificar un nombre enter canvia la seva _id_, en realitat estem creant un nou objecte amb el nou valor, però que si modifiquem una llista la seva _id_ no canvia: ```python x = 5 print(f"{id(x)=}", x) x += 1 print(f"{id(x)=}", x) ``` ```python x = [5] print(f"{id(x)=}", x) x[0] += 1 print(f"{id(x)=}", x) x.append(23) print(f"{id(x)=}", x) ``` Aquesta característica que sembla anecdòtica, es torna important quan passem variables com a paràmetres a una funció. Observem el següent exemple: ```python def incrementa_inmutable(x): x += 1 return x def incrementa_mutable(x): x[0] += 1 return x i = 9 m = [9] incrementa_inmutable(i) incrementa_mutable(m) print(f"{i=}") print(f"{m=}") ``` Aquest resultat que a primera vista pot semblar incoherent és el resultat intrínsec de que els objectes siguin mutables o inmutables. Tornem a veure un altre cop l'exemple anterior, però aquesta vegada mostrant la id de les variables tan a dins com a fora de les funcions i abans i desprès de les modificacions: ```python def incrementa_inmutable(x): print(f"----- Dins de la funció (i): {id(x)=}") x += 1 print(f"----- *Dins de la funció (i): {id(x)=}") return x def incrementa_mutable(x): print(f"Dins de la funció (m): {id(x)=}") x[0] += 1 print(f"*Dins de la funció (m): {id(x)=}") return x i = 9 m = [9] print(f"----- Abans de la funció: {id(i)=}") print(f"Abans de la funció: {id(m)=}") incrementa_inmutable(i) incrementa_mutable(m) print(f"{i=}") print(f"{m=}") print(f"----- Desprès de la funció: {id(i)=}") print(f"Desprès de la funció: {id(m)=}") ``` Podem observar que en el cas dels objectes inmutables que es modifiquen dins d'una funció, les modificacions es desen en un objecte diferent del que es passa per paràmetre i per tant no es poden veure fora de la funció que les ha modificat.