Programação orientada a objetos - Parte 3

Contents

Programação orientada a objetos - Parte 3#

Self#

Com a palavra-chave self conseguimos acessar os atributos e métodos de uma classe em Python. Ela é responsável por vincular os atributos com os argumentos enviados para uma função ou método.

O python utiliza essa palavra pois não há a sintaxe @ ou this para referenciar os atributos de instância. O self é sempre o primeiro parâmetro de todos os métodos chamados por uma instância de uma classe (ou seja, um objeto).

Self está sempre apontando para o objeto atual.

Vejamos nosso primeiro exemplo abaixo. A classe teste tem dentro do seu construtor uma mensagem para imprimir o endereço da variável self:

class teste:
    def __init__(self):
        print("Referência do self= ",id(self))
obj = teste()
print("Referência do objeto classe teste=", id(obj))
Referência do self=  2461971144080
Referência do objeto classe teste= 2461971144080

O init é o construtor da classe teste, significa que sempre que um novo objeto for instanciado a mensagem “Endereço do self: “ será executado. Nesse exemplo conseguimos comprovar que a variável self e o objeto obj possuem o mesmo endereço de memória, ou seja, representam a mesma coisa.

Agora vamos estudar um exemplo com atributos na classe.

class carro():
    def __init__(self, modelo, cor):
        self.modelo = modelo
        self.cor = cor

    def mostrar(self):
        print("O modelo é", self.modelo)
        print("A cor é", self.cor)
audi = carro("audi A4", "azul")
ferrari = carro ("ferrari 488", "verde")
audi.mostrar()
O modelo é audi A4
A cor é azul
ferrari.mostrar()
O modelo é ferrari 488
A cor é verde

Definimos a classe carro com dois parâmetros, modelo e cor. Podemos observar que a palavra self é sempre utilizada como primeiro argumento, tanto do construtor quanto do método mostrar. Nem quando instanciamos os objetos, nem quando chamamos o método mostrar utilizamos esse primeiro argumento self, o python passa essa chamada do método como se estivesse chamando carro.mostrar(audi) ou carro.mostrar(ferrari), vejam os exemplos abaixo:

Portanto, apesar de utilizarmos o self como primeiro argumento na definição de classes e métodos, não precisamos utilizá-lo na chamada. Mas o que acontece se não declararmos o self como primeiro parâmetro na definição? Será que essa palavra é opcional, servindo apenas para melhorar a legibilidade?

Vamos testar:

class teste_2:
    def __init__():
        print("Esse é o construtor")

objeto_2 = teste_2()
print("deu certo")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[10], line 5
      2     def __init__():
      3         print("Esse é o construtor")
----> 5 objeto_2 = teste_2()
      6 print("deu certo")

TypeError: teste_2.__init__() takes 0 positional arguments but 1 was given

Vejam que o python não aceitou o construtor sem o self. Assim chegamos a uma conclusão:

O self é sempre o primeiro argumento a ser passado em um construtor e nos métodos de instâncias.

O último teste que faremos é a utilização de outro parâmetro no lugar do self, será que self é uma palavra reservada e teremos erro?

class teste_3:
    def __init__(outro_self):
        print("Usando outro parâmetro no lugar de self")

objeto_3 = teste_3()
print("deu certo")
Usando outro parâmetro no lugar de self
deu certo

Não teremos nenhum erro, pois a realidade é que o self não é uma palavra reservada, é apenas uma convenção de boa prática. Melhora a legibilidade.

O self é uma convenção e não uma palavra reservada

É possível utilizar outras palavras no lugar do self, mas preste atenção de utilizá-la em todos os lugares daquele método onde o self iria aparecer. Vejam os dois casos abaixo:

class carro():
    def __init__(outro, modelo, cor):
        self.modelo = modelo
        self.cor = cor

    def mostrar(self):
        print("O modelo é", self.modelo)
        print("A cor é", self.cor)

fusca = carro('fusca','amarelo')
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[13], line 10
      7         print("O modelo é", self.modelo)
      8         print("A cor é", self.cor)
---> 10 fusca = carro('fusca','amarelo')

Cell In[13], line 3, in carro.__init__(outro, modelo, cor)
      2 def __init__(outro, modelo, cor):
----> 3     self.modelo = modelo
      4     self.cor = cor

NameError: name 'self' is not defined

E aqui a execução funcionaria sem problemas:

class carro():
    def __init__(outro, modelo, cor):
        outro.modelo = modelo
        outro.cor = cor

    def mostrar(self):
        print("O modelo é", self.modelo)
        print("A cor é", self.cor)

fusca = carro('fusca','amarelo')

fusca.mostrar()
O modelo é fusca
A cor é amarelo