Partilhar: WhatsApp
aulify
UC UC00608 · T. Desenv. Software

Ficha 01 · Classes e encapsulamento

Definir classes, atributos, métodos, properties
Versão · Aluno
Tempo · 60 minutos
Cotação · 100 pontos
Aluno(a)
Turma
Data
Objectivos da ficha

Parte I · Classes

Exercício 1 · Classe Livro (15 pts)

Cria uma classe Livro com atributos titulo, autor, ano, paginas. Adiciona método descrever() que devolve string formatada. Testa criando 2 livros e imprimindo.

class Livro:
    def __init__(self, titulo, autor, ano, paginas):
        self.titulo = titulo
        self.autor = autor
        self.ano = ano
        self.paginas = paginas

    def descrever(self):
        return f"'{self.titulo}' de {self.autor} ({self.ano}, {self.paginas}p)"

l1 = Livro("Os Lusíadas", "Camões", 1572, 600)
l2 = Livro("Saramago", "Ensaio sobre a cegueira", 1995, 350)

print(l1.descrever())
print(l2.descrever())

Exercício 2 · Método repr (10 pts)

Adiciona __repr__ e __str__ à classe Livro. Qual a diferença entre os dois?

class Livro:
    def __init__(self, titulo, autor, ano):
        self.titulo = titulo
        self.autor = autor
        self.ano = ano

    def __repr__(self):
        return f"Livro({self.titulo!r}, {self.autor!r}, {self.ano})"

    def __str__(self):
        return f"'{self.titulo}' — {self.autor}"

l = Livro("Saramago", "Ensaio sobre a cegueira", 1995)
print(repr(l))   # Livro('Saramago', ...)  — para programadores
print(str(l))    # 'Saramago' — Saramago   — para utilizadores
print(l)         # usa __str__

Diferença: - __repr__ — representação inequívoca para programadores; idealmente código que recria o objecto. - __str__ — representação legível para utilizadores. Se não definida, usa __repr__.

Parte II · Encapsulamento

Exercício 3 · Conta bancária (20 pts)

Cria classe ContaBancaria com: - Atributo "privado" _saldo. - Métodos depositar(valor), levantar(valor), saldo(). - Levantar deve falhar com excepção se saldo insuficiente ou valor negativo.

class ContaBancaria:
    def __init__(self, titular, saldo_inicial=0):
        self.titular = titular
        self._saldo = saldo_inicial

    def depositar(self, valor):
        if valor <= 0:
            raise ValueError("Valor tem de ser positivo")
        self._saldo += valor

    def levantar(self, valor):
        if valor <= 0:
            raise ValueError("Valor tem de ser positivo")
        if valor > self._saldo:
            raise ValueError("Saldo insuficiente")
        self._saldo -= valor

    def saldo(self):
        return self._saldo

# Teste
c = ContaBancaria("Ana", 100)
c.depositar(50)
print(c.saldo())     # 150
c.levantar(30)
print(c.saldo())     # 120
# c.levantar(1000)   # ValueError

Exercício 4 · Properties (15 pts)

Adiciona à ContaBancaria uma property saldo (em vez do método) e validar que o titular tem mínimo 3 caracteres no construtor.

class ContaBancaria:
    def __init__(self, titular, saldo_inicial=0):
        if len(titular) < 3:
            raise ValueError("Titular tem de ter pelo menos 3 caracteres")
        self.titular = titular
        self._saldo = saldo_inicial

    @property
    def saldo(self):
        return self._saldo

    # Sem setter — saldo só muda por depositar/levantar

    def depositar(self, valor):
        if valor <= 0:
            raise ValueError("Valor positivo")
        self._saldo += valor

    def levantar(self, valor):
        if valor <= 0 or valor > self._saldo:
            raise ValueError("Inválido")
        self._saldo -= valor

c = ContaBancaria("Ana", 100)
print(c.saldo)       # 150 — sem parêntesis
# c.saldo = 9999     # AttributeError — não há setter

Parte III · Métodos especiais

Exercício 5 · Classe Vetor (20 pts)

Cria classe Vetor com x, y. Implementa: - __init__ - __repr__ - __add__ — soma de vectores. - __eq__ — comparação. - __abs__ — magnitude.

import math

class Vetor:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Vetor({self.x}, {self.y})"

    def __add__(self, outro):
        return Vetor(self.x + outro.x, self.y + outro.y)

    def __eq__(self, outro):
        return isinstance(outro, Vetor) and self.x == outro.x and self.y == outro.y

    def __abs__(self):
        return math.sqrt(self.x**2 + self.y**2)

v1 = Vetor(3, 4)
v2 = Vetor(1, 2)
print(v1 + v2)       # Vetor(4, 6)
print(abs(v1))       # 5.0
print(v1 == Vetor(3, 4))  # True

Parte IV · Cenário

Exercício 6 · Sistema de aluguer (20 pts)

Modela um sistema de aluguer de bicicletas com:

from datetime import datetime

class Bicicleta:
    def __init__(self, id, modelo):
        self.id = id
        self.modelo = modelo
        self.disponivel = True

    def alugar(self, cliente):
        if not self.disponivel:
            raise ValueError(f"Bicicleta {self.id} não disponível")
        self.disponivel = False
        return Aluguer(self, cliente, datetime.now())

    def __repr__(self):
        status = "✓" if self.disponivel else "✗"
        return f"Bicicleta({self.id}, {self.modelo}, {status})"


class Aluguer:
    def __init__(self, bicicleta, cliente, inicio):
        self.bicicleta = bicicleta
        self.cliente = cliente
        self.inicio = inicio
        self.fim = None

    def terminar(self):
        if self.fim is not None:
            raise ValueError("Aluguer já terminado")
        self.fim = datetime.now()
        self.bicicleta.disponivel = True

    def duracao(self):
        if self.fim is None:
            return datetime.now() - self.inicio
        return self.fim - self.inicio

    def __repr__(self):
        estado = "em curso" if self.fim is None else "terminado"
        return f"Aluguer({self.cliente}, {self.bicicleta.id}, {estado})"

# Teste
b1 = Bicicleta(1, "BTT")
a = b1.alugar("Ana")
print(b1)            # disponível: ✗
print(a)             # em curso
a.terminar()
print(b1)            # disponível: ✓