Python

Orientação a objetos em Python

Veja neste artigo os principais conceitos do paradigma orientação a objetos e como eles se aplicam no Python.

há 3 anos 1 mês

Formação Desenvolvedor Python
Conheça a formação em detalhes

O paradigma de programação orientado à objetos é um dos principais paradigmas das linguagens de programação. Muito utilizado no mercado, entender como funciona e como implementar este paradigma é essencial para todo desenvolvedor de software.

No Python, o paradigma orientado à objetos funciona de forma similar às outras linguagens, porém com algumas mudanças em sua implementação, como veremos ao longo deste artigo.

Declarando classes

No paradigma orientado à objetos, uma classe é a representação de algo do mundo real. No Python, o uso de classes é algo constante no desenvolvimento de programas.

Sendo assim, para declarar uma classe no Python é bem simples, como podemos ver abaixo:

class Pessoa():
		# Atributos e métodos da classe

Como vimos acima, para declarar uma classe no Python, utilizamos a palavra reservada class seguido do nome desta classe.

No Python, todas as classes devem, por boas práticas, possuir nomes que comecem com letra maiúscula e, caso sejam compostos, a primeira letra de cada palavra deve ser maiúscula, o que chamamos de formato CamelCase:

class PessoaFisica():
    # Atributos e métodos da classe

Criando construtor da classe

Uma classe é representada por atributos e métodos. Os atributos de uma classe representam as características que esta classe possui, já os métodos representam o comportamento da classe.

Para declarar um atributo em uma classe no Python é bem simples, basta definir o nome do atributo no método especial chamado __init__, este método define o construtor da classe, ou seja, é onde definimos como uma nova pessoa será criada em nosso programa.

Para definir os atributos de uma classe em seu construtor, basta passá-los como parâmetro, como podemos ver abaixo:

class Pessoa:
    def __init__(self, nome, sexo, cpf):
        self.nome = nome
        self.sexo = sexo
        self.cpf = cpf

Agora, estamos indicando que toda pessoa que for criada em nosso programa e que utilize como base a classe Pessoa deverá possuir um nome, sexo e cpf.

Instanciando objetos

Como vimos anteriormente, as classes representam a estrutura de um elemento no mundo real, porém ela é apenas o modelo destes elementos.

Sempre que precisamos criar “algo” com base em uma classe, dizemos que estamos “instanciando objetos”. O ato de instanciar um objeto significa que estamos criando a representação de uma classe em nosso programa.

Para instanciar um objeto no Python com base em uma classe previamente declarada, basta indicar a classe que desejamos utilizar como base e, caso possua, informar os valores referentes aos seus atributos, como podemos ver abaixo:

class Pessoa:
    def __init__(self, nome, sexo, cpf):
        self.nome = nome
        self.sexo = sexo
        self.cpf = cpf

if __name__ == "__main__":
    pessoa1 = Pessoa("João", "M", "123456")
    print(pessoa1.nome)

Ao executar a linha pessoa1 = Pessoa("João", "M", "123456")estamos criando um objeto do tipo pessoa com nome “João”, sexo “M” e cpf “123456”.

Com isso, agora possuímos uma forma de criar diversas pessoas utilizando a mesma base, a classe Pessoa.

Ao executar o código acima e imprimir o nome dessa pessoa print(pessoa1.nome), teremos o seguinte retorno:

Instanciando objetos em Python

Declarando métodos

Como vimos anteriormente, uma classe possui atributos (que definem suas características) e métodos (que definem seus comportamentos).

Imagine que possuímos um atributo ativo na classe Pessoa. Toda pessoa criada em nosso sistema é inicializado como ativo, porém, imagine que queremos alterar o valor deste atributo e, assim, “desativar” a pessoa em nosso sistema e, além disso, exibir uma mensagem de que a pessoa foi “desativada com sucesso”.

Para isso, precisamos definir um comportamento para essa pessoa, assim, agora, ela poderá ser “desativada”.

Sendo assim, precisamos definir um método chamado “desativar” para criar este comportamento na classe Pessoa, como podemos ver abaixo:

class Pessoa:
    def __init__(self, nome, sexo, cpf, ativo):
        self.nome = nome
        self.sexo = sexo
        self.cpf = cpf
        self.ativo = ativo
        
    def desativar(self):
        self.ativo = False
        print("A pessoa foi desativada com sucesso")

if __name__ == "__main__":
    pessoa1 = Pessoa("João", "M", "123456", True)
    pessoa1.desativar()

Para criarmos este “comportamento” na classe Pessoa, utilizamos a palavra reservada def, que indica que estamos criando um método da classe, além do nome do método e seus atributos, caso possuam.

Depois disso, é só definir o comportamento que este método irá realizar. Neste caso, o método vai alterar o valor do atributo “ativo” para “False” e imprimir a mensagem “A pessoa foi desativada com sucesso”, como podemos ver abaixo:

Declarando métodos em Python

Declarando propriedades

Aparentemente o código acima funciona normalmente. Porém, temos um pequeno problema com o atributo “ativo”: ele é acessível para todo mundo. Ou seja, mesmo possuindo o método “desativar”, é possível alterar o valor do atributo “ativo” sem qualquer problema:

Declarando propriedades em Python

Este comportamento do nosso programa dá brechas para que um usuário possa ser ativado ou desativado sem passar pelo método responsável por isso. Por isso, para corrigir este problema, devemos recorrer a um pilar importantíssimo da Orientação à Objetos: o encapsulamento.

Basicamente, o encapsulamento visa definir o que pode ou não ser acessado de forma externa da classe.

Existem três tipos de atributos de visibilidade nas linguagens orientadas a objetos, que são:

  • Public: Atributos e métodos definidos como públicos poderão ser invocados, acessados e modificados através de qualquer lugar do projeto;
  • Private: Atributos e métodos definidos como privados só poderão ser invocados, acessados e modificados somente por seu próprio objeto.
  • Protected: Atributos e métodos definidos como protegidos só poderão ser invocados, acessados e modificados por classes que herdam de outras classes através do conceito de Herança, visto na última aula. Sendo assim, apenas classes “filhas” poderão acessar métodos e atributos protegidos.

No Python, diferente das linguagens completamente voltadas ao paradigma da orientação à objetos (Java, C#, etc.), estes atributos existem, mas não da forma “convencional”.

Python - Fundamentos
Curso Python - Fundamentos
Conhecer o curso

Para definir um atributo público, não há necessidade de realizar nenhuma alteração, por padrão, todos os atributos e métodos criados no Python são definidos com este nível de visibilidade.

Já se precisarmos definir um atributo como privado, adicionamos dois underlines (__) antes do nome do atributo ou método:

class Pessoa:
    def __init__(self, nome, sexo, cpf, ativo):
        self.nome = nome
        self.sexo = sexo
        self.cpf = cpf
        self.__ativo = ativo
        
    def desativar(self):
        self.__ativo = False
        print("A pessoa foi desativada com sucesso")

if __name__ == "__main__":
    pessoa1 = Pessoa("João", "M", "123456", True)
    pessoa1.desativar()
    pessoa1.ativo = True
    print(pessoa1.ativo)

Porém, isso é apenas uma “convenção” do Python, ou seja, mesmo definindo o atributo com visibilidade privada (utilizando dois underlines antes de seu nome), ele poderá ser acessado de fora da classe:

Declarando propriedades em Python

Isso ocorre porquê estamos falando de “convenções”, ou seja, padrões que devem ser seguidos por desenvolvedores Python.

Porém, caso precisemos acessar os atributos privados de uma classe, o Python oferece um mecanismo para construção de propriedades em uma classe e, dessa forma, melhorar a forma de encapsulamento dos atributos presentes. É comum que, quando queremos obter ou alterar os valores de um atributo, criamos métodos getters e setters para este atributo:

class Pessoa:
    def __init__(self, nome, sexo, cpf, ativo):
        self.__nome = nome
        self.__sexo = sexo
        self.__cpf = cpf
        self.__ativo = ativo
        
    def desativar(self):
        self.__ativo = False
        print("A pessoa foi desativada com sucesso")
        
    def get_nome(self):
        return self.__nome
    
    def set_nome(self, nome):
        self.__nome = nome

if __name__ == "__main__":
    pessoa1 = Pessoa("João", "M", "123456", True)
    pessoa1.desativar()
    pessoa1.ativo = True
    print(pessoa1.ativo)
    
    # Utilizando geters e setters
    pessoa1.set_nome("José")
    print(pessoa1.get_nome())

Porém, ao tentar acessar o valor do atributo nome presente na classe, fica evidente que estamos obtendo esse dado através de um método. Pensando nisso, o time de desenvolvimento criou as Properties para prover um meio mais “elegante” para obter e enviar novos dados aos atributos de uma classe:

class Pessoa:
    def __init__(self, nome, sexo, cpf, ativo):
        self.__nome = nome
        self.__sexo = sexo
        self.__cpf = cpf
        self.__ativo = ativo
        
    def desativar(self):
        self.__ativo = False
        print("A pessoa foi desativada com sucesso")
        
		def get_nome(self):
        return self.__nome
    
    def set_nome(self, nome):
        self.__nome = nome

    @property
    def nome(self):
        return self.__nome
    
    @nome.setter
    def nome(self, nome):
        self.__nome = nome

if __name__ == "__main__":
    pessoa1 = Pessoa("João", "M", "123456", True)
    pessoa1.desativar()
    pessoa1.ativo = True
    print(pessoa1.ativo)
    
		# Utilizando geters e setters
    pessoa1.set_nome("José")
    print(pessoa1.get_nome())

    # Utilizando properties
    pessoa1.nome = "José"
    print(pessoa1.nome)

Com isso, podemos ver o quão mais “limpo” é o uso das properties para acessar ou alterar o valor de uma propriedade privada das classes no Python.

Se você quer conhecer mais sobre Python, acesse nosso guia da linguagem.

Autor(a) do artigo

Ana Paula de Andrade
Ana Paula de Andrade

Graduanda em Sistemas de Informação pelo Instituto Federal da Bahia. É responsável pelo atendimento ao cliente, gerenciamento de redes sociais e revisão de cursos, além da redação de artigos para o blog da TreinaWeb.

Todos os artigos

Artigos relacionados Ver todos