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:
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 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:
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”.
Curso Python - Fundamentos
Conhecer o cursoPara 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:
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.