---
# System prepended metadata

title: 'ASIX M3. [UF2]. Abast i mutabilitat.'
tags: [' programació modular', ' funcions', ' programació', asix]

---

---
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.
