11.3 Invocando O Método Reescrito

Depois de reescrito, não podemos mais chamar o método antigo que fora herdado da classe mãe, pois realmente alteramos o seu comportamento. Todavia, podemos invocá-lo no caso de estarmos dentro da classe.

Imagine que para calcular a bonificação de um Gerente , devemos fazer igual ao cálculo de um

Funcionario , adicionando 1000.0 reais. Poderíamos fazer assim:

class Gerente(Funcionario):
python
def __init__(self, senha, qtd_gerenciaveis): self._senha = senha self._qtd_gerenciaveis = qtd_gerenciaveis
 
def get_bonificacao():
 
return self._salario \* 0.10 + 1000.0 # métodos e properties
 
Aqui teríamos um problema: o dia que o get_bonificacao() do Funcionario mudar, precisaremos mudar o método do Gerente para acompanhar a nova bonificação. Para evitar isso, o get_bonificacao() do Gerente pode chamar o do Funcionario utilizando o método **super()**.
 
python
class Gerente(Funcionario):
python
def __init__(self, senha, qtd_gerenciaveis): self._senha = senha self._qtd_gerenciaveis = qtd_gerenciaveis
 
def get_bonificacao():
 
return super().get_bonificacao() + 1000 # métodos e properties
 
Essa invocação vai procurar o método com o nome get_bonificacao() de uma superclasse de
 

Gerente . No caso, ele logo vai encontrar esse método em Funcionario .

Essa é uma prática comum, pois em muitos casos o método reescrito geralmente faz algo a mais que o método da classe mãe. Chamar ou não o método de cima é uma decisão e depende do seu problema. Algumas vezes, não faz sentido invocar o método que reescrevemos.

Para escrever uma classe utilizando o Python 2, é preciso acrescentar a palavra ‘object’ quando definimos uma classe:

class MinhaClasse(object):

pass

Isso acontece porque toda classe é filha de object - que é chamada a mãe de todas as classes. No Pyhton, toda classe herda de object. No Python 3, não precisamos acrescentar o object, mas não quer dizer que esta classe e a herança não existam, apenas que a mesma é implícita. Quando criamos uma classe vazia e utilizamos o método dir() para checar a lista de seus atributos, reparamos que ela não é vazia:

class MinhaClasse(): pass
python
if name == ' main ': mc = MinhaClasse() print(dir(mc))

Gerando a saída:

[’ class ’, ’ delattr ’, ’ dict ’, ’ dir ’, ’ doc ’, ’ eq ’, ’ format ’, ’ ge ’, ’ getattribute ’, ’ gt ’, ’ hash ’,

’ init ’, ’ init_subclass ’, ’ le ’, ’ lt ’, ’ module ’ ’ ne ’, ’ new ’, ’ reduce ’, ’ reduce_ex ’, ’ repr ’,

’ setattr ’, ’ sizeof ’, ’ str ’, ’ subclasshook ’, ’ weakref ’]

Todos estes atributos são herdados da classe object e podemos reescrever qualquer um deles na nossa subclasse. Todos eles são os conhecidos métodos ‘mágicos’ (começam e iniciam com dois underscores, e por este motivo, também chamados de dunders).

Vimos o comportamento do init () , new () e do dict . Outros métodos mágicos famosos são str () e repr () - métodos que retornam a representação do objeto como uma string. Quando chamamos print(mc) temos a saída

< main .MinhaClasse object at 0x7f11c1f59a58>

Esse é o modelo padrão de impressão de um objeto, implementado na classe object . A função print() na verdade usa a string definida pelo método str () de uma classe. Vamos reescrever este método:

class MinhaClasse:
python
def str (self):
 
return f'< Instância de {}; endereço:{}> {self. class . name , id(self}')
 
Agora, quando executamos print(mc) , a saída é:
 
<Instância de MinhaClasse; endereço:0x7f11c1f59a58>
 
O Python sempre chama o método str () quando utiliza a função print() em um objeto.
 
Novamente, estamos utilizando reescrita de métodos.
 
O método repr () também retorna uma string , e podemos utilizar a função repr() para checar seu retorno:
 
python
class MinhaClasse(): pass
python
if name == ' main ': mc = MinhaClasse() print(repr(mc))

Que vai gerar a mesma saída padrão do str () :

< main .MinhaClasse object at 0x7f11c1f59a58>

Mas diferente do str () , não é comum sobrescrever este método. Ele é sobrescrito quando precisamos utilizá-lo junto com a função eval() do Python. A função eval() recebe uma string e tenta executar essa string como um comando do Python. Veja um exemplo de uso:

x =

eval(“x+1”)

Vamos a um exemplo utilizando classes:

class Ponto:
python
def __init__(self, x, y): self.x = x
 
self.y = y
 
def str (self):
 
return f'({}, {}) {self.x, self.y}'
 
def repr (self):
 
return f'Ponto({}, {}) {self.x + 1, self.y + 1}'
 
java
if name == ' main ': p1 = Ponto(1, 2)

p2 = eval(repr(p1))

print(p1) print(p2)

Se executarmos o código acima, temos:

(1, 2)

(2, 3)

Repare que utilizamos a função repr() passando uma instância de Ponto . O Python vai chamar então o método repr () da classe Ponto , que retorna a string “Ponto(2, 3)” já que p1.x = 1 e p1.y = 2 . Ao passá-la de argumento para a função eval() , teremos: p2 = eval(‘Ponto(2, 3)) . Como a função eval() vai tentar executar essa string como um comando Python válido ele terá sucesso, e portanto p2 será uma nova instância da classe Ponto com p2.x = 2 e p2.y = 3 .

Para concluir, é importante entender que tanto str () quanto repr () retornam uma string que representa o objeto, mas com propósitos diferentes. O método str () é utilizado para apresentar mensagens para os usuários da classe, de maneira mais amigável. Já o método

repr () é usado para representar o objeto de maneira técnica, inclusive podendo utilizá-lo como comando válido do Python, como vimos no exemplo da classe Ponto .‌‌


⬅️ Capítulo Anterior | Próximo Capítulo ➡️