python

Unitat Didàctica 5: Classes en POO

Concepte de Classe en Python

Una classe és una plantilla que serveix per crear objectes. Defineix quins atributs (dades) i mètodes (funcions) tindran aquests objectes.

Exemple bàsic de definició de classe

class Cotxe:
    def __init__(self, marca, model):
        self.marca = marca
        self.model = model

    def mostrar_info(self):
        print(f"{self.marca} {self.model}")

🚗 Creació d’objectes a partir de la classe

cotxe1 = Cotxe("Toyota", "Corolla")
cotxe2 = Cotxe("Ford", "Focus")

cotxe1.mostrar_info()  # Toyota Corolla
cotxe2.mostrar_info()  # Ford Focus

Parts d'una classe

Component Descripció
class Paraula clau per crear una classe
__init__() Constructor: defineix com s'inicialitza l’objecte
self Referència a l'objecte actual
Atributs Informació de l’objecte (com self.marca)
Mètodes Funcions dins la classe (com mostrar_info())

🧾 Resum ràpid

Concepte Significat
Classe Plantilla per crear objectes
Objecte Instància concreta d’una classe
Atribut Característica de l’objecte (com el nom o l’edat)
Mètode Acció o comportament de l’objecte

🎓 Exemple de la vida real

Estructura i Membres d'una Classe en Python

Una classe en Python és una plantilla per crear objectes. Conté atributs (dades) i mètodes (funcions) que defineixen el comportament i l’estat dels objectes.

Estructura bàsica

class NomClasse:
    atribut_classe = valor

    def __init__(self, paràmetres):
        self.atribut_instancia = valor

    def metode(self):
        pass

Membres d'una classe

Tipus Descripció Exemple
Atribut de classe Compartit per tots els objectes atribut_classe = 0
Atribut d’instància Únic per a cada objecte self.nom = "Anna"
Constructor Inicialitza l’objecte def __init__(self):
Mètode d’instància Opera sobre l’objecte (usa self) def parlar(self):
Mètode de classe Opera sobre la classe (usa @classmethod) def crear(cls):
Mètode estàtic No depèn ni de la classe ni de l’objecte def ajuda():

Exemple complet

class Persona:
    especie = "Humà"  # Atribut de classe

    def __init__(self, nom, edat):
        self.nom = nom          # Atribut d’instància
        self.edat = edat

    def saludar(self):          # Mètode d’instància
        print(f"Hola! Sóc {self.nom}.")

    @classmethod
    def info_especie(cls):      # Mètode de classe
        print(f"Tots som {cls.especie}")

    @staticmethod
    def ajuda():                # Mètode estàtic
        print("Usa __init__ per crear objectes.")

Resum ràpid

Membre Funció Accés
atribut_classe Valor comú a tots els objectes Classe.nom
self.atribut Valor específic de cada objecte Només via instància
@classmethod Treballa amb la classe (cls) Classe.metode()
@staticmethod No usa ni self ni cls Classe.metode()
__init__ Constructor de l'objecte Executat automàticament

Visibilitat en Classes en Python

En Python, la visibilitat determina si un atribut o mètode d'una classe és accessible des de fora. Python no fa servir paraules clau com public o private, però utilitza convencions amb els noms.

Tipus de visibilitat

Tipus Com s’escriu Accessible des de fora? Comentari
Pública self.nom ✅ Sí Qualsevol pot accedir
Protegida self._nom ⚠️ Sí (es desaconsella) Convenció per indicar ús intern
Privada self.__nom 🚫 No directament Només accessible dins la classe

🔧 Exemple de codi

class Persona:
    def __init__(self, nom, edat):
        self.nom = nom           # Públic
        self._edat = edat        # Protegit
        self.__dni = "12345678Z" # Privat

    def mostrar_info(self):
        print(f"Nom: {self.nom}, Edat: {self._edat}")

    def mostrar_dni(self):
        print(f"DNI: {self.__dni}")

p = Persona("Anna", 30)

print(p.nom)        #  ✅ Públic   ->  mostra : Anna
print(p._edat)      # ⚠️ Protegit  ->  mostra: 30
# print(p.__dni)    # ❌ Error: No accessible directament  -> mostra error

p.mostrar_dni()     # ✅ Accés a privat amb mètode  -> mostra:  DNI: 12345678Z

🔍 Name Mangling (accedir a atributs privats)

Els atributs privats es poden accedir si coneixes el nom intern generat per Python:

print(p._Persona__dni)  # ✅ Possible (però no recomanat)

Resum ràpid

Notació Tipus Accés extern Ús recomanat
atribut Públic ✅ Sí Per atributs oberts
_atribut Protegit ⚠️ Sí Ús intern o per subclasses
__atribut Privat 🚫 No (excepte amb truc) Per ocultar dades sensibles

Mètodes especials

Mètodes màgics o “dunder”

Els mètodes especials comencen i acaben amb dos guions baixos (__). Se'ls anomena sovint “dunder” (de l'anglés “Double UNDERscore”).

Exemple amb __str__

class Persona:
        def __init__(self, nom, edat):
            self.nom = nom
            self.edat = edat

        def __str__(self):
            return f"{self.nom}, {self.edat} anys"

    persona = Persona("Anna", 30)
    print(persona)  # Output: Anna, 30 anys
        

Altres mètodes dunder habituals:

Per veure tots els mètodes i atributs disponibles d’un objecte pots utilitzar:

print(dir(obj))

Herència

La herència permet a una classe (filla) adquirir els atributs i mètodes d’una altra classe (pare). És un dels pilars de la POO i facilita la reutilització de codi i l’organització jeràrquica.

Estructura bàsica

class ClassePare:
    # atributs i mètodes

class ClasseFilla(ClassePare):
    # hereta tot i pot afegir o modificar

🧪 Exemple bàsic

class Animal:
    def parlar(self):
        print("Fa algun so")

class Gos(Animal):
    def parlar(self):  # sobrescriu
        print("Bup bup!")

class Gat(Animal):
    def parlar(self):
        print("Miau!")

a = Animal()
a.parlar()   # Fa algun so

g = Gos()
g.parlar()   # Bup bup!

cat = Gat()
cat.parlar() # Miau!

Cridar el constructor del pare amb super()

class Persona:
    def __init__(self, nom):
        self.nom = nom

class Estudiant(Persona):
    def __init__(self, nom, curs):
        super().__init__(nom)
        self.curs = curs

Notes:


Encapsulació

En Python, pots controlar l'accés als atributs mitjançant modificadors d'accés:

Exemple:


    class CompteBancari:
        def __init__(self, titular, saldo):
            self.titular = titular
            self.__saldo = saldo  # Atribut privat
    
        def depositar(self, quantitat):
            self.__saldo += quantitat
    
        def mostrar_saldo(self):
            print(f"Saldo: {self.__saldo}")
    
    compte = CompteBancari("Carlos", 1000)
    compte.depositar(500)
    compte.mostrar_saldo()  # Output: Saldo: 1500
        

Nota: Encara que els atributs privats no es poden accedir directament, es poden consultar mitjançant mètodes públics. Python també permet accedir-hi usant el nom modificat (_Classe__atribut), però això no es recomana.


Polimorfisme

El polimorfisme permet que diferents classes tinguen un mateix mètode però amb comportaments diferents.

Exemple:


    class Au:
        def so(self):
            print("Cant genèric")
    
    class Canari(Au):
        def so(self):
            print("Trinar")
    
    class Ànec(Au):
        def so(self):
            print("Quac quac")
    
    animals = [Canari(), Ànec(), Au()]
    for animal in animals:
        animal.so()
        

En aquest exemple, encara que totes les classes comparteixen el mètode so(), cada una executa una acció diferent. Això és una aplicació del polimorfisme.

Classes Iterables

Pots crear els teus propis iterables definint una classe que implemente els mètodes __iter__() i __next__(). Això et permet crear seqüències personalitzades que es poden recórrer amb bucles for.

Exemple d'un iterable personalitzat:

class Comptador:
        def __init__(self, inici, fi):
            self.inici = inici
            self.fi = fi
    
        def __iter__(self):
            self.numero = self.inici
            return self
    
        def __next__(self):
            if self.numero <= self.fi:
                resultat = self.numero
                self.numero += 1
                return resultat
            else:
                raise StopIteration
    
    comptador = Comptador(1, 5)
    
    for numero in comptador:
        print(numero)
        

En aquest exemple, la classe Comptador és un iterable que genera nombres del 1 al 5. El bucle for recorre cada nombre generat per l'iterable i el mostra per consola.


Exercicis

Els exercicis i tests corresponents a esta unitat es troben en Aules