Salta el contingut
 

Exercicis: Programació orientada a objectes

Joan Puigcerver Ibáñez

Llicència: CC BY-NC-SA 4.0

(Reconeixement - NoComercial - CompartirIgual) 🅭

Objectius

En aquests exercicis es treballen:

  • Definició de classes en Python.
  • Atributs d'instància i de classe.
  • Mètodes d'instància i especials.
  • Encapsulament bàsic i validació de dades.

Els exercicis marcats amb ✅ seran corregits a classe.

Estructura del projecte

Tots els exercicis han de complir l'estructura següent:

  • Cada exercici ha d'anar dins del directori corresponent.
  • El nom del fitxer ha de coincidir amb el títol de l'exercici.
  • El format de l'eixida del programa ha de ser consistent amb el format demanat.
  • La lògica d'aplicació ha d'estar organitzada en classes i mètodes; és recomanable afegir docstrings.

Exercicis

ud4/exercises

✅ person.py

Crea una classe Person amb els atributs name i age.

Afegeix els mètodes següents:

  • greet(): mostra per pantalla el text amb el format:
    Hola, sóc {name} i tinc {age} anys.
    
  • is_adult(): retorna True si age >= 18 o False en cas contrari.
  • __str__(): retorna una cadena amb una representació amb el format:
    Person(name={name}, age={age})
    

L'execució principal del programa ha de crear una instància de Person a partir de dades llegides per entrada estàndard i cridar els mètodes definits.

Exemple: Ús
Entrada
Introdueix el nom: Marta
Introdueix l'edat: 20
Eixida
Hola, sóc Marta i tinc 20 anys.
És major d'edat: True
Representació: Persona(nom=Marta, edat=20)

✅ rectangle.py

Crea una classe Rectangle amb els atributs següents:

  • x: posició en l'eix X del vèrtex inferior esquerre.
  • y: posició en l'eix Y del vèrtex inferior esquerre.
  • width: ample del rectangle.
  • height: alt del rectangle.

Implementa els mètodes següents:

  • Rectangle(width, height, x=0, y=0): constructor que inicialitza els atributs.
  • area(): retorna l'àrea del rectangle.
  • perimeter(): retorna el perímetre del rectangle.
  • is_square(): retorna True si el rectangle és un quadrat.
  • set_position(x, y): estableix la posició del rectangle a (x, y).
  • move(dx, dy): desplaça el rectangle en dx i dy.
  • contains(px, py): retorna True si el punt (px, py) està dins del rectangle.
  • __str__(): retorna una cadena amb la representació del rectangle.
Exemple: Ús
r = Rectangle(3, 4, x=1, y=1)
print("Area:", r.area())
print("Perimeter:", r.perimeter())
print("Is square:", r.is_square())
print("Contains (2, 2):", r.contains(2, 2))
Area: 12
Perimeter: 14
Is square: False
Contains (2, 2): True

circle.py

Crea una classe Circle amb els atributs següents:

  • x: posició en l'eix X (centre).
  • y: posició en l'eix Y (centre).
  • radius: radi del cercle.

Implementa els mètodes següents:

  • __init__(radius, x=0, y=0): constructor que inicialitza el radi i la posició. Ha de validar que el radi siga positiu.
  • area(): retorna l'àrea del cercle.
  • circumference(): retorna la circumferència del cercle.
  • set_radius(new_radius): permet canviar el radi, aplicant la mateixa validació.
  • contains(px, py): retorna True si el punt (px, py) es troba dins o a la vora del cercle.
  • __str__(): retorna una cadena amb la representació del cercle amb el format:
    Circle(radius={radius}, center=({x}, {y}))
    

Pots utilitzar math.pi per accedir a la constant \(\pi\)

Exemple: Ús
c = Circle(radius=5, x=1, y=1)
print(c)
print(f"Àrea: {c.area():.2f}")
print(f"Circumferència: {c.circumference():.2f}")
print("Conté el punt (3, 3):", c.contains(3, 3))
print("Conté el punt (7, 7):", c.contains(7, 7))
Eixida
Circle(radius=5, center=(1, 1))
Àrea: 78.54
Circumferència: 31.42
Conté el punt (3, 3): True
Conté el punt (7, 7): False

✅ library.py

Crea la classe Library que permetrà emmagatzemar instàncies de la classe Book, els quals tenen els atributs isbn, title, year.

La classe Library ha de tindre els mètodes següents:

  • books(): retorna una llista amb els llibres.
  • find(isbn): retorna el llibre amb l'ISBN indicat. Si no existeix, retorna None.
  • contains(isbn): retorna True si existeix un llibre amb l'ISBN indicat.
  • add(book): afegeix un llibre a la biblioteca.
  • remove(isbn): elimina i retorna el llibre amb l'ISBN indicat. Si no s'ha trobat, retorna None.
  • size(): retorna el nombre de llibres.
  • print_books(): mostra per pantalla la llista dels llibres amb el format:
    - {isbn}: {title} ({year})
    

El programa ha de mostrar un menú que permeta a la persona usuària realitzar les accions següents:

  • Afegir un nou llibre.
  • Eliminar un llibre existent per ISBN.
    • Informarà del llibre que s'ha eliminat.
    • Mostrarà un missatge d'error si no s'ha trobat.
  • Mostrar els llibres existents.
    • Indicarà si encara no hi ha cap llibre a la biblioteca.

✅ robot.py

Implementa i prova la classe Robot que representa un robot que es pot moure en un pla bidimensional (2D).

classDiagram
    class Robot {
        - x
        - y
        - speed
        + Robot(x, y, speed)
        + accelerate()
        + decelerate()
        + up()
        + down()
        + left()
        + right()
        + \_\_str\_\_()
    }
Atributs
  • x, y: coordenades del robot.
  • speed: velocitat del robot.
Constructors
  • Robot(x, y, speed): crea un robot a les coordenades i velocitat especificades.
    • Per defecte, el valor de tots els atributs és 0.
    • La velocitat ha d'estar entre 0 i 10.
    • Si s'especifica per baix de 0, la velocitat serà 0.
    • Si s'especifica per dalt de 10, la velocitat serà 10.
Mètodes
  • accelerate(): incrementa la velocitat del robot en 0.5. La velocitat màxima és 10.
  • decelerate(): redueix la velocitat del robot en 0.5. La velocitat mínima és 0.
  • up(): mou el robot cap amunt segons la seua velocitat.
  • down(): mou el robot cap avall segons la seua velocitat.
  • left(): mou el robot cap a l'esquerra segons la seua velocitat.
  • right(): mou el robot cap a la dreta segons la seua velocitat.
  • __str__(): retorna una representació en text del robot amb les seues coordenades i velocitat.

    Robot(x=0.0, y=0.0, speed=1.0)
    

timer.py

Crea la classe Timer que funcione com un temporitzador simple.

  • Timer(seconds): crea un temporitzador amb els segons indicats.
  • tick(): disminueix el temps en 1 segon.
  • reset(): reinicia el temporitzador al temps inicial.
  • add(seconds): afegeix els segons especificats al temporitzador.
  • __str__(): retorna una representació en format hh:mm:ss.

Implementa Timer.from_str(str), que construeix un temporitzador a partir d'un str amb el format hh:mm:ss.

user-account.py

Crea la classe UserAccount que representa un compte d'usuari d'un sistema Linux.

Atributs:

  • username: nom d'usuari.
  • uid: identificador d'usuari. Ha de ser un enter positiu.
  • gid: identificador de grup. Ha de ser un enter positiu.
  • home: directori d'inici.
  • shell: intèrpret d'ordres per defecte.

Mètodes:

  • __str__(): retorna una cadena amb la representació del compte d'usuari amb el format:
    UserAccount(username={username}, uid={uid}, gid={gid}, home={home}, shell={shell})
    
  • format_passwd(): retorna una cadena amb el format del fitxer /etc/passwd:
    {username}:{uid}:{gid}:{home}:{shell}
    
  • is_system_user(): retorna True si el uid és menor que 1000 o False en cas contrari.

L'entrada principal del programa ha de crear instàncies de UserAccount i guardar-les en una llista a partir de línies llegides des de l'entrada estàndard en el format del fitxer /etc/passwd.

Exemple: Ús
Entrada
root:x:0:0:/root:/bin/bash
alice:x:1001:1001:/home/alice:/bin/zsh
bob:x:1002:1002:/home/bob:/bin/bash
Eixida
UserAccount(username=root, uid=0, gid=0, home=/root, shell=/bin/bash)
És usuari del sistema: True
Format /etc/passwd: root:0:0:/root:/bin/bash

UserAccount(username=alice, uid=1001, gid=1001, home=/home/alice, shell=/bin/zsh)
És usuari del sistema: False
Format /etc/passwd: alice:1001:1001:/home/alice:/bin/zsh

UserAccount(username=bob, uid=1002, gid=1002, home=/home/bob, shell=/bin/bash)
És usuari del sistema: False
Format /etc/passwd: bob:1002:1002:/home/bob:/bin/bash

✅ permissions.py

Crea una classe Permissions que representa els permisos d'una persona usuària sobre un recurs.

Atributs
  • read (booleà)
  • write (booleà)
  • execute (booleà)
Mètodes
  • __str__(): retorna una representació en format rwx, on cada lletra apareix si el permís està activat, o - si no.

    Exemple: r-x (read i execute, sense write)

  • enable(permission): activa un permís ('r', 'w' o 'x').

  • disable(permission): desactiva un permís.
  • toggle(permission): canvia l'estat d'un permís.
  • has(permission): retorna True si el permís està activat.
  • __eq__(other): compara si dos conjunts de permisos són iguals.
  • __or__(other): retorna un nou objecte Permissions amb la unió dels permisos.
  • __and__(other): retorna un nou objecte Permissions amb la intersecció dels permisos.
Exemple: Ús
p1 = Permissions(read=True, write=False, execute=True)
p2 = Permissions(read=True, write=True, execute=False)

print(p1)        # r-x
print(p2)        # rw-
print(p1 & p2)   # r--
print(p1 | p2)   # rwx
print(p1 == p2)  # False
p1.enable('w')
print(p1)        # rwx

ip-address.py

Crea la classe IpAddress que representa una adreça IP.

La creació d'una IP vindrà donada a partir d'un str amb el format: X.X.X.X\N, on X és cadascun dels bytes i N són els bits de la màscara de subxarxa.

El programa ha de validar que els valors són correctes:

  • X ha d'estar entre 0 i 255.
  • N ha d'estar entre 1 i 30.

Ha de proporcionar els mètodes següents:

  • __str__(): retorna la representació de la IP en el format X.X.X.X\N.
  • ip_address(): retorna la IP com a cadena X.X.X.X.
  • subnet_mask(): retorna la màscara de subxarxa en format X.X.X.X.
  • net_address(): retorna la IP de la xarxa.
  • broadcast(): retorna la IP de broadcast de la xarxa.
  • is_net_address(): retorna True si és una adreça de xarxa.
  • is_broadcast(): retorna True si és una adreça de broadcast.
  • is_host_address(): retorna True si és una adreça d'un amfitrió vàlida.
  • is_on_subnet(ip): retorna True si la IP indicada està dins de la mateixa subxarxa.
  • __eq__(), __lt__(), __le__(), __gt__(), __ge__(): per comparar adreces IP.
📌 Aquest document pot quedar desactualitzat després d’imprimir-lo. Pots consultar la versió més recent a la pàgina web.
🌿 Abans d’imprimir aquest document, considera si és realment necessari. Redueix el consum de paper i ajuda a protegir el nostre entorn.