Dijous, febrer 12, 2026
PROGRAMACIÓ

Variables i assignacions a Python: constants, convencions, reassignació i ús de type() i id()

Python no té declaracions de variables a l’estil de C o Java. No s’ indica el tipus ni es reserven espais explícitament: s’ assigna un valor a un nom i l’ intèrpret s’ encarrega de la resta. Això simplifica la sintaxi, però també deixa més marge per cometre errors si no s’entén bé com funciona internament.

Aquest text cobreix les bases i matisos que convé tenir clars des del començament: com es nomenen variables, com es tracten les constants, què significa reassignar, què passa realment amb els objectes en memòria i com es fan servir funcions com a type() i id() per inspeccionar el que passa.

1. Assignació a Python: el que realment passa

A Python, l ‘ assignació no copia dades en una adreça de memòria fixa associada a una variable. El que es fa és crear una referència: un nom (identificador) apunta a un objecte en memòria.

x = 42
  • Es crea un objecte sencer amb valor 42 (si no existia ja en memòria).
  • El nom x s’ associa a aquest objecte.

Això implica que:

  • No s’emmagatzema el valor directament en la variable, sinó que la variable és una etiqueta per a un objecte.
  • Un mateix objecte pot tenir diverses etiquetes (àlies).
  • Canviar un nom perquè apunti a un altre objecte no afecta altres noms que apuntaven a l’anterior.

Exemple:

a = [1, 2, 3]
b = a  # b i a apunten a la mateixa llista
b.append(4)
 
print(a)  # [1, 2, 3, 4]
print(b)  # [1, 2, 3, 4]

Aquí, a i b són referències al mateix objecte. No hi ha còpia automàtica.


2. Noms i convencions

Python és sensible a majúscules i minúscules: variable i Variable són diferents noms. Les convencions de noms no afecten el comportament de l’intèrpret, però sí a la llegibilitat i manteniment.

2.1 Convencions comunes (PEP 8)

  • Variables normals: minuscules_amb_guions_baixos.  Exemple: total_vendes, comptador
  • Constants (per convenció): MAJUSCULES_AMB_GUIONS_BAIXOS. Exemple: PI = 3.14159, MAX_CONNEXIONS = 100
    (Python no impedeix reassignar una constant, és només un acord entre desenvolupadors).
  • Variables internes/privades: _prefixe_amb_guio_baix indica que alguna cosa no s’hauria de fer servir fora del mòdul o classe. No hi ha privacitat real, només un senyal.
  • Especials: __doble_guio_baix__ reservats per a mètodes i atributs especials del propi Python. Exemple: __init__, __len__.

No seguir aquestes convencions no espatlla el codi, però ho fa més difícil de mantenir i entendre per d’altres.

3. Constants: el que Python no fa per tu

En molts llenguatges, declarar una constant implica que el compilador o intèrpret impedirà canviar el seu valor. A Python, no existeix aquesta protecció:

PI = 3.14159
PI = 3 # Cap error: el valor es reassigna

3.1 Solucions parcials

  • Disciplina d’ equip: respectar l’ ús de majúscules per a constants i no reassignar-les.
  • Ús de mòduls de només lectura: col·locar les “constants” en un mòdul i no modificar-les en la resta del codi.
  • typing. Final (des de Python 3.8) per indicar a eines d’anàlisi estàtica que alguna cosa no ha de canviar:
from typing import Final
 
PI: Final = 3.14159

Això no bloqueja la reassignació en temps d’execució, però linters i analitzadors poden advertir.

4. Reassignació: què significa a Python

Quan es “canvia” el valor d’una variable, en realitat es fa que el nom apunti a un altre objecte.

x = 10
x = 20

El nom x abans apuntava a un objecte enter 10 i ara apunta a un altre objecte enter 20. L’ enter 10 queda sense referències i serà eliminat pel recol·lector d’ escombraries.

Això és diferent a modificar un objecte mutable:

llista = [1, 2, 3]
llista.append(4) # Es modifica l'objecte en si

Al primer cas (x = 20) canviem la referència; al segon (append) el nom continua apuntant al mateix objecte, però aquest objecte ha canviat internament.

5. Fer servir type() per inspeccionar objectes

La funció integrada type(obj) retorna el tipus de l’objecte al qual apunta un nom.

x = 3.14
print(type(x))  # <class 'float'>
 
x = "text"
print(type(x))  # <class 'str'>

Això és útil per a depuració, validacions o aprenentatge. També es pot fer servir per crear classes dinàmicament, però aquest ús és avançat.

Detall important:
 actua sobre l’objecte, no sobre el nom. Si dos noms apunten al mateix objecte, type() retornarà el mateix per a tots dos.

6. Fer servir id() per entendre referències

id(obj) retorna un identificador únic per a un objecte mentre estigui viu en memòria. A CPython és la direcció de memòria, però no s’ha de dependre d’això.

a = [1, 2, 3]
b = a
print(id(a), id(b))  # Mateix valor: apunten al mateix objecte
 
b = [1, 2, 3]
print(id(a), id(b)) # Diferents: objectes diferents encara que tinguin el mateix contingut

Això ajuda a diferenciar entre dues variables que comparteixen objecte i dues que tenen còpies amb el mateix valor.

7. Exemples pràctics de type() i id() combinats

Per veure com canvien les referències i els tipus durant l’ execució:

x = 5
print(type(x), id(x))  # <class 'int'>, id de 5
 
x = x + 1
print(type(x), id(x))  # <class 'int'>, id diferent: nou objecte
 
y = [1, 2]
print(type(y), id(y))  # <class 'list'>, id de la llista
 
y.append(3)
print(type(y), id(y))  # <class 'list'>, id igual: es modifica el mateix objecte

Aquí es veu que els enters són immutables: cada operació que “canvia” el valor crea un objecte nou. Les llistes són mutables: es modifiquen al mateix lloc de memòria.

8. Assignació múltiple i encadenada

Python permet assignar diversos noms en una sola línia:

a, b, c = 1, 2, 3

També es pot fer assignació encadenada:

x = y = z = []

En aquest cas, tots apunten al mateix objecte llista. Modificar-lo a través d’ un nom afectarà a tots:

x.append(1)
print(y)  # [1]
print(z)  # [1]

Això és una font comuna d’errors. Si la intenció és crear llistes separades, cal fer-ho explícitament:

x, y, z = [], [], []

9. Àmbit de les variables

Una variable existeix en un àmbit (scope) concret:

  • Local: dins d’ una funció.
  • No local: en funcions niuades (fent servir nonlocal).
  • Global: definida al mòdul.
  • Integrada: noms que Python porta per defecte (len, type, etc.).

Entendre això és crucial per evitar trepitjar valors per accident i per comprendre per què de vegades un canvi dins d’una funció no afecta fora.

10. Àlies involuntaris i efectes col·laterals

A Python, dos noms diferents poden referir-se al mateix objecte sense que sigui obvi a primera vista. Això succeeix molt en treballar amb objectes mutables.

Exemple típic amb llistes:

original = [1, 2, 3]
còpia = original # No és una còpia real
copia.append(4)
 
print(original)  # [1, 2, 3, 4]
print(copia)     # [1, 2, 3, 4]

L’append a través de còpia també afecta original perquè ambdós noms apunten al mateix objecte. Per comprovar-ho ràpidament:

print(id(original) == id(copia))  # True

Si se’ n vol una còpia real, cal crear-la explícitament:

copia = original.copy()
# o
copia = list(original)
# o amb slicing
còpia = original[:]

En aquest cas:

print(id(original) == id(copia))  # False

11. Objectes mutables i immutables i la seva relació amb l’assignació

A Python, el comportament de la reassignació i la modificació depèn de si l’ objecte és mutable o immutable:

  • Immutables: int, float, str, tuple, frozenset, bool. No es poden canviar després de creats. Les operacions creen nous objectes.
  • Mutables: list, dict, set, instàncies de classes personalitzades (en general). Es poden modificar al mateix lloc de memòria.

Això implica que:

a = 10
b = a
b += 1
print(a, b)  # 10, 11

Aquí b += 1 crea un nou sencer i b apunta a ell. a queda intacte.

Però amb llistes:

a = [1, 2]
b = a
b += [3] # Igual a a a.extend([3])
print(a, b)  # [1, 2, 3] [1, 2, 3]

b segueix apuntant al mateix objecte que a, i el modifica.

12. Ús de type() per a validacions simples

Tot i que Python és de tipat dinàmic, type() pot ajudar a controlar entrades o validar dades:

def procesar(numero):
    if type(numero) is not int:
        raise TypeError("S'esperava un enter")
    return numero * 2

Per a tipus complexos i herència, millor usar isinstance():

if not isinstance(valor, (int, float)):
    ...

isinstance() detecta subclasses, mentre que type() només compara tipus exactes.

13. Ús d’id() a depuració i optimització

id() és molt útil per saber si dos noms comparteixen el mateix objecte, especialment quan el contingut s’ assembla.

Cas amb enters petits:

a = 256
b = 256
print(id(a) == id(b))  # True
 
a = 257
b = 257
print(id(a) == id(b))  # A CPython, normalment False

Python reutilitza internament certs objectes immutables petits (interning). Això pot confondre si no s’ entén:

x = "hola"
y = "hola"
print(id(x) == id(y))  # True per interning de cadenes curtes

Per això no convé usar id() per a lògica de negoci; és una eina de diagnòstic.

14. Casos especials d’assignació

14.1 Desempaquetatge

Python permet assignar múltiples valors d’un iterable en una sola instrucció:

x, y = (1, 2)

També amb asterisc per capturar “la resta”:

a, *b = [1, 2, 3, 4]
# a = 1, b = [2, 3, 4]

14.2 Intercanvi de valors

No cal fer servir una variable temporal:

a, b = b, a

Això crea una tupla temporal (b, a) i la desempaqueta als nous valors.

15. Errors comuns

  • Confondre còpia amb àlies en mutables.
  • Fer servir assignació encadenada amb mutables sense entendre que comparteixen objecte.
  • Esperar que type() verifiqui herència (per a això, isinstance()).
  • Dependre d’id() com a identificador global (no garantit entre execucions ni implementacions).
  • Reassignar “constants” creient que Python ho prohibeix.

16. Resum operatiu

  • L’assignació a Python vincula noms a objectes, no valors a caixes fixes.
  • Les “constants” són per convenció, no per imposició del llenguatge.
  • La reassignació canvia la referència, no l’ objecte.
  • type() retorna el tipus de l’objecte; isinstance() és més flexible.
  • id() permet veure si dos noms comparteixen el mateix objecte.
  • Entendre mutabilitat evita errors subtils amb àlies i canvis inesperats.

Deixa un comentari

L'adreça electrònica no es publicarà. Els camps necessaris estan marcats amb *