# dades i comportament, junts

Introducció a la POO en Python

Un dict agrupa dades; una classe hi afegeix comportament propi. És el pas final d'un camí que ja havies començat amb les estructures.

Per què classes?

Al capítol d'estructures vas veure un dict fent de "struct": agrupant dades (nom, edat) sota un sol nom. Però les dades soles no basten — recorda aniversari(p), una funció a part que calia cridar passant-li el diccionari.

Una classe permet unir la dada i el comportament que hi actua: en lloc de aniversari(jordi), escriuràs jordi.aniversari() — l'objecte i les seves accions, junts.

Definir una classe

Exemple

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

p1 = Persona("Jordi", 16)
print(p1.nom, p1.edat)

__init__ és el constructor: s'executa automàticament en crear un objecte nou (Persona("Jordi", 16)), i és on li assignes els atributs inicials. self és l'objecte mateix — sempre el primer paràmetre de qualsevol mètode, encara que mai l'escriguis en cridar-lo.

p1 és una instància de la classe Persona: un objecte concret, amb els seus propis valors. Pots crear-ne tants com vulguis (p2 = Persona("Anna", 20)), cadascun independent.

Mètodes

Un mètode és una funció definida dins la classe, que actua sobre self.

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

    def aniversari(self):
        self.edat = self.edat + 1

p1 = Persona("Jordi", 16)
p1.aniversari()
print(p1.edat)   # 17

Compara p1.aniversari() amb l'aniversari(jordi) del capítol d'estructures: el mateix efecte (incrementar l'edat), però ara la funció viu dins de la pròpia classe, i la crides sobre l'objecte directament.

__str__ com es mostra un objecte

Per defecte, print(p1) mostraria alguna cosa críptica com <__main__.Persona object at 0x...>. El mètode especial __str__ et deixa triar què es mostra.

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

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

p1 = Persona("Jordi", 16)
print(p1)   # Jordi (16 anys)

print() crida __str__ tot sol quan li passes un objecte: mai l'escrius tu mateix com p1.__str__().

bonus C++ també en té

Tot aquest material estava basat en C/C++, i C++ (a diferència de C) sí que té classes — amb una sintaxi semblant: class Persona { public: string nom; int edat; void aniversari() { edat++; } };. Els conceptes (constructor, mètodes, objectes) són els mateixos; només canvia la sintaxi concreta.

Mira els objectes crear-se i canviar pas a pas

Fixa't en com self sempre fa referència a l'objecte sobre el qual s'ha cridat el mètode.

Classes i objectes

Codi

Variables

NomValor

Terminal

Pas 1 / 1

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

Defineix una classe Rectangle amb amplada i alcada, i dos mètodes: area() i perimetre().

Àrea: 20
Perímetre: 18
Pistes

def area(self): return self.amplada * self.alcada — un mètode no necessita cap paràmetre més enllà de self si tot el que li cal ja és als seus propis atributs.

2. Comptador de clics

Defineix una classe ContadorClics amb un comptador intern que comença a 0, un mètode clic() que l'incrementa, i un mètode valor() que el retorna.

0
1
2
Pistes

__init__(self) no necessita cap paràmetre més: simplement fa self.comptador = 0.

Crea un objecte, imprimeix c.valor(), fes c.clic() un parell de cops, imprimint c.valor() cada vegada.

3. Persona amb __str__

Defineix una classe Persona amb nom i edat, un mètode es_major_edat() que retorni True/False, i un __str__ que la mostri de forma llegible.

Jordi (16 anys)
És major d'edat? False
Pistes

def es_major_edat(self): return self.edat >= 18.

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?