• Python
  • 12. Python intermediário
  • Classes

11. Python intermediário: Classes#

Aprendemos muitas coisas sobre Python e programação até agora. E com o que aprendemos é possível começar a produzir códigos complexos.

Talvez você já tenha percebido que os nossos códigos foram aumentando de tamanho conforme o conteúdo da disciplina avançava. E isso é só o começo! Conforme os programas vão ganhando linhas e linhas de código, precisamos de estruturas para nos ajudar na organização.

Já aprendemos alguns conceitos que nos auxiliam na hora de construir e organizar o código. Por exemplo, aprendemos a utilizar funções, listas e dicionários.

  • Funções: As funções ajudam a evitar repetição de código. Podemos pensar em funções como se fossem nomes que damos a um trecho de código;
  • Listas: As listas nos ajudam a trabalhar com muitos valores sem precisar criar uma variável para cada valor.
  • Dicionários: Os dicionários podem ser vistos como uma evolução das listas, onde trabalhamos com chaves ao invés de ficarmos limitados aos índices numéricos. Além disso, os dicionários nos possibilitam representar dados mais complexos, como o dicionário a seguir que possui dados referentes a animais de estimação:
    dicionario = {
      "Lili": {"espécie":"gato", "idade": 5},
      "Thor": {"espécie":"cachorro", "idade": 3},
      "Paçoca": {"espécie":"hamster", "idade": 1}
    }
    

Neste handout vamos ver outro recurso conhecido como classe. Na disciplina Developer Life não vamos entrar em detalhes sobre o que são classes, nem como montar boas classes. Queremos apenas saber o mínimo para poder utilizá-las.

Neste primeiro momento você pode entender uma classe como um tipo de dados do Python. Na verdade, já trabalhamos com algumas classes, por mais que não tenhamos chamado-as assim: listas, strings e dicionários são algumas das classes disponíveis na linguagem. O interessante é que podemos criar novas classes (ou tipos) no Python. A ideia é semelhante ao que fazemos com um def. Primeiro definimos a classe e depois usamos quando for necessário. Suponha, por exemplo, que queremos criar um novo tipo que represente um ponto com coordenadas x e y. Ele poderia ser feito da seguinte maneira (o exemplo completo está no arquivo teste_ponto.py):

class Point:
    def __init__(self):
        self.x = 0
        self.y = 0

O trecho de código class Point: define uma classe Point que possui coordenadas x e y ambas iguais a zero.

Note que apenas definimos esse novo tipo, mas ainda não usamos. A partir desse momento o Python sabe o que é uma lista, o que é uma string e agora também sabe o que é um Point. Vamos utilizar esse nosso novo tipo!

Com calma 😌

Não explicamos os novos trechos de código: def __init__(self):, self.x e self.x. E talvez não tenha ficado muito claro como eles funcionam, mas vamos olhar com mais calma para eles novamente mais para frente.

Exercise 1

Considere o código a seguir:

ponto = Point()
print('O ponto está nas coordenadas x={0} e y={1}'.format(ponto.x, ponto.y))

Ao testar o código acima, o que foi impresso no terminal?

Answer

O código acima vai imprimir: O ponto está nas coordenadas x=0 e y=0. O x e y são variáveis (chamamos de atributos) que estão ligadas àquele ponto específico.

Exercise 2

Podemos inclusive mudar o valor do ponto:

ponto = Point()
ponto.x = 2
ponto.y = 5
print('O ponto está nas coordenadas x={0} e y={1}'.format(ponto.x, ponto.y))
Ao testar o código acima, o que foi impresso no terminal?

Answer

Esse novo código vai imprimir: O ponto está nas coordenadas x=2 e y=5.

Podemos modificar a nossa classe para que ela receba como argumentos os valores das coordenadas assim que um novo ponto é criado:

class Point:
    def __init__(self, x_coord, y_coord):
        self.x = x_coord
        self.y = y_coord

ponto = Point(4, 1)
print('O ponto está nas coordenadas x={0} e y={1}'.format(ponto.x, ponto.y))

Exercise 3

Ao testar o código acima, o que foi impresso no terminal?

Answer

Esse novo código vai imprimir: O ponto está nas coordenadas x=4 e y=1. Perceba que os valores para self.x e self.y não são definidos como o valor 0. Trocamos os 0`s pelos argumentos x_coord e x_coord.

A função __init__ é um tipo de função especial que é chamada quando o novo ponto é criado. Duas observações importantes:

  • São dois underscores no começo e dois underscores no fim (chamamos esse par de dois underscores de dunder, ou double underscore);
  • Essas funções que fazem parte de uma classe sempre recebem um primeiro argumento chamado self. Ele é uma variável que guarda o próprio objeto. No nosso exemplo, self é o próprio ponto. Por isso, quando fazemos self.x = 0 estamos guardando na variável (atributo) x desse ponto específico o valor 0.

Talvez você tenha notado que ao criar um ponto com o código ponto = Point(4, 1) não passamos o argumento self.

Criando um ponto.

Como o self é uma referência ao próprio ponto, então não precisamos passar ele quando estamos criando o ponto.

Vamos ver mais um exemplo de uma função definida dentro da classe (também chamada de método):

class Point:
    def __init__(self, x_coord, y_coord):
        self.x = x_coord
        self.y = y_coord

    def distance_to(self, other_point):
        dx = other_point.x - self.x
        dy = other_point.y - self.y
        return ((dx**2) + (dy**2)) ** 0.5

Exercise 4

Considere o código acima. Agora definimos um método para a classe Point, chamado distance_to.

O que você acha que o método distance_to faz.

Answer

O método distance_to recebe dois pontos como argumento. O primeiro ponto é o self e o segundo argumento é other_point.

Exercise 5

O código abaixo cria dois pontos p1 e p2 e depois utiliza o nosso novo método distance_to.

class Point:
    def __init__(self, x_coord, y_coord):
        self.x = x_coord
        self.y = y_coord

    def distance_to(self, other_point):
        dx = other_point.x - self.x
        dy = other_point.y - self.y
        return ((dx**2) + (dy**2)) ** 0.5

p1 = Point(4, 1)
p2 = Point(7, 5)
d = p1.distance_to(p2)
print('A distância de ({0}, {1}) a ({2}, {3}) é {4}'.format(p1.x, p1.y, p2.x, p2.y, d))

Ao testar o código acima, o que foi impresso no terminal?

Answer

O programa acima vai imprimir: A distância de (4, 1) a (7, 5) é 5.

Exercise 6

Considere o mesmo código do exercício anterior:

class Point:
    def __init__(self, x_coord, y_coord):
        self.x = x_coord
        self.y = y_coord

    def distance_to(self, other_point):
        dx = other_point.x - self.x
        dy = other_point.y - self.y
        return ((dx**2) + (dy**2)) ** 0.5

p1 = Point(4, 1)
p2 = Point(7, 5)
d = p1.distance_to(p2)
print('A distância de ({0}, {1}) a ({2}, {3}) é {4}'.format(p1.x, p1.y, p2.x, p2.y, d))

Ao executar a linha 7, com o código, dx = other_point.x - self.x. Quais são os valores de other_point.x e self.x respectivamente.

Answer

Os valores para other_point.x e self.x são 7, 4.

Valores para other_point.x e self.x

Considere o comando na penúltima linha: d = p1.distance_to(p2). Ele segue uma estrutura muito parecida com o que já fazíamos com strings, por exemplo:

s = 'Insper'
t = s.replace('Ins', 'Su')
print(t)

EXERCÍCIOS#

Agora tente praticar um pouco.

Exercise 7

Resolva o exercício Classe retângulo.

Acessar exercício

Exercise 8

Resolva o exercício Carrinho de compras.

Acessar exercício

Exercise 9

Resolva o exercício Classe Foguete.

Acessar exercício