Aula Prática 5 - Definição de Classes de Objetos

Esta aula consiste numa iniciação à definição de classes de objetos. Após a realização da prática, deverá ter sido adquirida uma noção básica dos seguintes conceitos:

  • Definição de uma classe, nomeadamente
  • atributos
  • construtores
  • operações e métodos (implementação das operações)

Trabalho Prévio

Neste primeiro contacto com a definição de uma classe de objetos, pretende-se desenvolver uma classe cujos objetos simulem uma calculadora. Nas calculadoras tipicamente temos um valor (inicialmente a zero) que guarda o resultado da última operação. Ao efetuar uma nova operação o valor guardado será utilizado.

Comece a resolver o exercício com base no seguinte código. O construtor definido no início da classe define o atributo __value e o procedimento (que altera o estado do objeto) é um método. Experimente esta classe, criando mais do que um objeto Calculator, e invocando o método add() em cada um deles. Defina uma propriedade que esconda o atributo __value, de modo a permitir a consulta do valor guardado na calculadora, podendo apenas ser alterado usando as operações da calculadora. Note que este aspeto é muito importante. Se tal não fosse feito, a atualização do valor guardado na calculadora poderia ser realizada de forma incorrecta.

    class Calculator:

        def __init__(self):
            self.__value = 0

        def add(self, n):
            self.__value = self.__value + n

        ...

Assumindo que a calculadora só funciona com números inteiros maiores ou iguais a zero, e não fazendo uso dos operadores *, ** , //, e %, complete-a com outras operações, nomeadamente:

  • Reset (o valor fica a zero)
  • Subtração
  • Multiplicação
  • Potência
  • Divisão
  • Resto da divisão
In [15]:
class Calculator:

    def __init__(self):
        self.__value = 0
        
    @property
    def value(self):
        return self.__value

    def add(self, n):
        self.__value = self.__value + n

    def reset(self):
        self.__value = 0
    
    def mult(self, n):
        v = self.__value
        i = 1
        while i < n:
            self.__value = self.__value + v
            i = i + 1

    def power(self, n):
        v = self.__value
        i = 1
        while i < n:
            # self.__value = self.__value * v
            self.mult(v)
            i = i + 1
In [16]:
c1 = Calculator()
c1.add(5)
c1.value
Out[16]:
5
In [17]:
c1.mult(4)
c1.value
Out[17]:
20
In [18]:
c1.reset()
c1.add(5)
c1.value
Out[18]:
5
In [19]:
c1.power(3)
c1.value
Out[19]:
125

Exercícios

1. Desenvolva uma classe para representar retângulos em termos da sua largura e altura.

Os objetos retângulo deverão ser imutáveis, significando que uma vez criados as suas dimensões já não podem ser alteradas. O método __init__ é um médodo construtor.

    class Rectangle:

        def __init__(self, width, height):
            self.__width = width
            self.__height = height

        ...

(a) Defina funções que permitam obter a seguinte informação sobre o retângulo:
- área
- perímetro
- comprimento da diagonal
- se o retângulo é um quadrado
(b) Defina funções que permitam obter um novo objeto retângulo:

i) escalando o retângulo dado um fator, por exemplo, escalar um retângulo 4x5 por 2 daria origem a um novo retângulo 8x10. Caso o fator seja igual a 1, deverá ser devolvido o próprio retângulo (self).

    def scale(self, factor):
        ...

ii) somando outro retangulo, por exemplo, o retângulo 3x4 somado com os valores 4 e 5 daria origem a um retângulo 7x9.

    def sum(self, width, height):
        ...
(c) Defina um função que recebendo como parâmetro um retângulo r, indica se o retângulo que invoca a função tem uma maior área do que r.
(d) Defina uma função fora da classe Rectangle que dados dois retângulos, devolve o retângulo que tem a área maior. Caso os retângulos tenham áreas iguais deverá ser devolvido o primeiro.
def max_rectangle(a, b):
    ...
In [1]:
class Rectangle:

    def __init__(self, w, h):
        self.__w = w
        self.__h = h

    def area(self):
        return self.__w * self.__h

    def perimetro(self):
        return 2 * self.__w + 2 * self.__h

    def diag(self):
        return (self.__w**2 + self.__h**2) **(1/2)

    def is_square(self):
        return self.__w == self.__h
    
    def scale(self, factor):
        return Rectangle( self.__w * f, self.__h * f)
    
    def sum(self, w, h):
        return Rectangle (self.__w + w, self.__h + h)
    
    def is_area_greater_than(self, r):
        return self.area() > r.area()
In [33]:
r1 = Rectangle(2,3)
r2 = Rectangle(3,4)
r1.area()
Out[33]:
6
In [31]:
r1.is_area_greater_than(r2)
Out[31]:
False
In [34]:
def max_rectangle(a, b):
    if a.area() >= b.area():
        return a
    else:
        return b
In [38]:
r3 = max_rectangle(r1,r2)
r3.area()
Out[38]:
12

2. Desenvolva uma classe de objetos para representar contactos telefónicos de pessoas.

Os contactos devem ter informação sobre o nome e o número de telefone de uma pessoa. O nome deve ser imutável; o número de telefone pode ser alterado.

In [39]:
class Contact:

    def __init__(self, name, phone):
        self.__name = name
        self.phone = phone

    @property
    def name(self):
        return self.__name

    def show(self):
        print("Name: ", self.name, " Phone:", self.phone)
In [41]:
p1 = Contact("Maria Albertina", 963555555)
p1.show()
p1.phone = 555555555
p1.show()
Name:  Maria Albertina  Phone: 963555555
Name:  Maria Albertina  Phone: 555555555

Exercícios Extra

Desenvolva uma classe Rational para representar números racionais (frações). Os objetos deverão ser imutáveis e deverá ser possível criar um número racional de duas formas: (a) dando apenas o numerador, ficando o denominador implicitamente igual a 1; (b) dando o numerador e o denominador. Defina métodos de instância que permitam:

  1. Obter o número real (float) representado pela fração.
  2. Obter o resultado da adição do número racional com outro número racional dado (devolvendo um objeto Rational).
  3. Obter o número racional multiplicado por um dado escalar (devolvendo um objeto Rational).
  4. Obter o resultado da multiplicação do número racional por outro número racional dado (devolvendo um objeto Rational).
  5. Verificar se o número racional é igual a um outro número racional dado.
  6. Verificar se o número racional é maior que um outro número racional dado.
In [ ]:
 

Other classes

In [42]:
class Point:

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

    @property
    def x(self):
        return self.x

    @property
    def y(self):
        return self.y


class Lamp:

    def __init__(self):
        self._is_on = False

    def turn_on(self):
        self._is_on = True

    def turn_off(self):
        self._is_on = False

    def is_on(self):
        return self._is_on
In [ ]: