Você sabe o que são classes no Python? Já ouviu falar de Programação Orientada a Objetos (POO)? Aprenda de uma vez por todas o que é POO e como ela pode transformar a maneira como você escreve seus códigos!
Se quiser pode acompanhar esse conteúdo em formato de vídeo ou pode acessar o nosso Canal do YouTube para mais vídeos!
O que você vai ver hoje?
Classes no Python – Guia Completo para Sair do Zero em POO
Se você já está estudando Python e deseja dominar a Programação Orientada a Objetos (POO), entender o conceito de classes é essencial!
Nesta aula, vou te guiar passo a passo pelos fundamentos da programação orientada a objetos. Vamos explorar juntos o que são classes, como criá-las e utilizá-las no Python.
Você aprenderá tanto a teoria quanto a prática por trás dos conceitos fundamentais: classes, objetos, atributos, métodos, self e init. Entenderemos como cada um desses elementos trabalha em conjunto para construir uma classe e criar objetos no Python.
Por fim, você verá como organizar o código em classes e objetos torna a programação mais simples, prática e eficiente.
O que é Programação Orientada a Objetos?
A Programação Orientada a Objetos (POO) é um paradigma que ajuda a organizar e estruturar melhor o código. No Python, a POO é uma abordagem fundamental para criar códigos modulares, reutilizáveis e mais fáceis de manter.
Quando pensamos em programação no Python, basicamente temos dois modelos principais:
- Programação Estrutural (Scripts): Código linear e direto, útil para pequenos projetos ou para resolver problemas simples.
- Programação Orientada a Objetos (POO): Organização do código em classes e objetos, ideal para projetos mais complexos, como sistemas e jogos.
Na POO, cada objeto possui atributos (características) e métodos (comportamentos), que são definidos por meio de classes.
O que são Classes e Objetos?
Uma classe é um modelo que define a estrutura de um objeto. Ela contém:
- Atributos: Variáveis que armazenam características do objeto.
- Métodos: Funções que definem o comportamento do objeto.
Já o objeto é uma instância dessa classe. Cada objeto criado a partir de uma classe herda os atributos e métodos definidos por ela, mas pode ter valores e estados específicos.
Em resumo, as classes no Python representam um conjunto de objetos com características e ações semelhantes.
Para entender melhor o conceito de classes e objetos, vamos usar um exemplo com carros.
Pense em um projeto de construção de carros (blueprint). Esse projeto seria o equivalente a uma classe. Ele define atributos que o carro pode ter, como cor, marca e modelo, e métodos, como acelerar, frear e buzinar.
Os objetos, por outro lado, são os carros reais criados a partir desse projeto. Cada carro pode ter características diferentes, como outra cor ou modelo, mas todos compartilham a mesma estrutura definida pela classe.
A partir da classe Carro, podemos criar objetos como carro1 e carro2. Veja como isso ficaria no Python:
# O projeto/molde (classe): class Carro: def __init__(self, cor, marca, modelo): # O que cada carro terá self.cor = cor # A cor do carro self.marca = marca # A marca do carro self.modelo = modelo # O modelo do carro def acelerar(self): # O que o carro pode fazer print("acelerando") def frear(self): # O que o carro pode fazer print("freando") def buzinar(self): # O que o carro pode fazer print("buzinando")
Agora, vamos criar alguns carros (objetos) usando essa classe:
# Criando os carros (objetos) usando o projeto (classe): carro1 = Carro("vermelho", "Fiat", "esportivo") # Um carro esportivo vermelho carro2 = Carro("azul", "Volkswagen", "SUV") # Um carro SUV azul
Perceba como cada carro é único, mas foi criado a partir da mesma classe. Podemos verificar as características dos carros e usar os métodos definidos na classe.
# Verificando os carros print(f"O carro 1 é {carro1.cor}, da marca {carro1.marca} e é do modelo {carro1.modelo}.") print(f"O carro 2 é {carro2.cor}, da marca {carro2.marca} e é do modelo {carro2.modelo}.")
# Usando os métodos de cada carro carro1.buzinar() carro2.acelerar()
Uma das grandes vantagens de usar classes e objetos é a reutilização de código e a organização estrutural que a POO oferece.
Ao agrupar atributos e métodos relacionados em uma única classe, o código fica mais modular, facilitando a manutenção e a expansão do projeto.
Além disso, a POO permite criar hierarquias de classes usando herança e polimorfismo, o que aumenta a flexibilidade e a eficiência do código.
Por exemplo:
- Com herança, podemos criar uma nova classe que herda os atributos e métodos de outra, adicionando ou modificando comportamentos.
- Com polimorfismo, é possível usar métodos de forma mais flexível, adaptando-os às necessidades específicas de cada objeto.
Criando sua Primeira Classe em Python
Agora que você já compreendeu os conceitos básicos envolvendo classes e objetos em Python, vamos criar um exemplo juntos a partir do zero, considerando o controle remoto de uma televisão.
Pense em quais características você quer que esse controle tenha, como cor, formato, largura, altura, peso, etc.
Em seguida, comece a planejar os métodos, ou seja, as funcionalidades que esse controle terá: mudar o canal, alterar o volume, ligar a TV, acessar a Netflix e assim por diante.
Classe ControleRemoto:
- Características do Controle:
- Cor
- Altura
- Profundidade
- Largura
- Métodos do Controle:
- Trocar o canal
- Alterar o volume
- Abrir a Netflix
- Desligar a TV
Agora que definimos o molde do nosso objeto, ou seja, a classe com suas características e métodos, vamos transformá-la em código Python.
Aqui, é importante nos atentarmos para uma função essencial das classes: a função __init__. Essa função, também chamada de “método construtor”, será responsável por criar o objeto da nossa classe.
Sempre que você criar uma classe, será necessário definir a função __init__ (com dois underlines no início e no final). Essa função inicializa a classe e é onde passamos todas as características necessárias para criar o objeto.
Pense nela como uma lista de instruções que é executada automaticamente quando o objeto é criado.
Além disso, ao estruturar a classe, vamos usar o self. O self é utilizado em classes no Python para indicar que você está referenciando, acessando ou modificando algo do próprio objeto (sejam eles atributos ou métodos).
Basicamente, o self funciona como um identificador que referencia o próprio objeto. Quando criamos a função __init__ ou algum método dentro de uma classe, o primeiro parâmetro desse método geralmente será a palavra self.
Isso permite que os métodos e atributos associados ao objeto possam ser acessados por outras funcionalidades existentes dentro da classe.
class ControleRemoto: # O método __init__ define as características do controle def __init__(self, cor, altura, profundidade, largura): self.cor = cor self.altura = altura self.profundidade = profundidade self.largura = largura # Método para trocar o canal def trocar_canal(self, canal): print(f"Canal trocado para {canal}.") # Método para alterar o volume def alterar_volume(self, volume): print(f"Alterando o volume para {volume}.") # Método para abrir a Netflix def abrir_netflix(self): print("Abrindo a Netflix...") # Método para desligar a TV def desligar_tv(self): print("Desligando a TV...")
Repare que a definição dos métodos da classe é semelhante à construção de funções em Python. Nesse caso, passamos o parâmetro self, além de outros parâmetros que os métodos possam receber no momento em que forem utilizados.
Criando um Objeto em Python – Acessando seus Atributos e Métodos
Após termos a estrutura da classe definida, podemos criar quantos objetos quisermos a partir dela. Neste caso, vamos criar dois controles remotos usando a classe ControleRemoto.
As características de cada controle serão passadas no momento em que criamos o objeto.
Internamente, o método __init__ será executado automaticamente, sendo responsável por criar o objeto e atribuir suas características aos atributos dele, como self.cor, self.altura, etc.
Esse é o papel do self: durante a criação do objeto, ele faz referência ao próprio objeto que está sendo criado. Isso permite que cada objeto tenha suas próprias características atribuídas de forma única e independente.
# Criando um controle remoto meu_controle = ControleRemoto("preto", 15, 2, 5) # Criando outro controle controle_reserva = ControleRemoto("cinza", 12, 3, 4)
Cada objeto é uma instância independente da classe ControleRemoto, com características próprias que podemos acessar individualmente.
print(meu_controle.cor) print(controle_reserva.cor)
Os métodos não precisam ser declarados no momento de criação do objeto. Isso ocorre porque todos os objetos criados a partir da classe ControleRemoto terão acesso às funcionalidades definidas dentro da classe.
Por exemplo, podemos abrir a Netflix com o meu_controle e trocar de canal com o controle_reserva:
meu_controle.abrir_netflix() controle_reserva.trocar_canal(10)
Note que ambos os métodos foram executados normalmente. A única diferença é que o método trocar_canal precisa de um argumento para funcionar corretamente, que, neste caso, é o número do canal.
Importante: Embora o self seja declarado no momento da definição do método, ele não precisa ser passado explicitamente quando chamamos o método de um objeto.
O self é uma referência ao objeto em si, e o Python cuida disso automaticamente durante a execução, permitindo que o método saiba a qual objeto ele pertence.
Exemplo Prático – Validando Atributos
Em sistemas reais, nem todos os valores devem ser aceitos como atributos sem validação.
Para visualizarmos como isso funciona, vamos criar um sistema simples para gerenciar clientes da Netflix. Nesse sistema, teremos a classe Cliente com os atributos nome, email e plano.
class Cliente: def __init__(self, nome, email, plano): self.nome = nome self.email = email self.plano = plano
Dessa forma, podemos criar quantos clientes da Netflix forem necessários, e esses clientes serão armazenados no banco de dados da Netflix.
cliente1 = Cliente("Lira", "[email protected]", "basic")
No entanto, vamos supor que a Netflix só ofereça os serviços dos planos Basic e Premium. Não existe nada no nosso sistema que impeça qualquer outro valor dentro do atributo plano.
Para isso, podemos criar na definição da classe uma validação que só aceitará valores dentro de uma lista determinada.
class Cliente: def __init__(self, nome, email, plano): self.nome = nome self.email = email lista_planos = ["basic", "premium"] if plano in lista_planos: self.plano = plano else: raise Exception("Plano inválido")
Dessa forma, caso algum processo dentro do sistema tente criar um cliente que não tenha recebido como atributo o plano basic ou premium, será exibido um erro de “plano inválido”.
cliente1 = Cliente("Lira", "[email protected]", "extraordinário")
No entanto, essa não é a melhor forma de fazer isso. Perceba que, dentro da função __init__, definimos a lista_planos como uma variável comum. Isso faz com que os valores armazenados nela só estejam disponíveis para essa função.
Portanto, imagine que você irá implementar uma funcionalidade nova que permite o cliente alterar o plano do qual ele faz parte.
Para alterar esse plano, você precisa verificar se o novo plano está na lista aprovada. Porém, como lista_planos não é um atributo do cliente, você não pode acessá-la em outras funções, como a função mudar_plano.
Para isso, basta utilizarmos a palavra self antes de lista_planos. Dessa forma, definimos que lista_planos é uma característica da classe Cliente, que pode ser acessada fora dela e por outros métodos presentes na classe.
lass Cliente: def __init__(self, nome, email, plano): self.nome = nome self.email = email self.lista_planos = ["basic", "premium"] if plano in self.lista_planos: self.plano = plano else: raise Exception("Plano inválido") def mudar_plano(self, novo_plano): if novo_plano in self.lista_planos: self.plano = novo_plano else: print("Plano inválido")
Por isso é tão importante que dentro da sua função __init__ você defina todos os atributos da sua classe, para que você possa utilizá-los em qualquer outro método criado dentro dela.
Agora, vamos testar esse sistema. Primeiro, criaremos o cliente com o plano basic, e em seguida iremos alterar para o plano premium.
cliente1 = Cliente("Lira", "[email protected]", "basic") print(cliente1.plano)
cliente1.mudar_plano("premium") print(cliente1.plano)
Veja que tudo funcionou corretamente. Apesar de ser um exemplo simples, o objetivo é que você entenda os conceitos de classe, métodos e atributos, para que possa aplicá-los em projetos maiores e mais complexos.
Herança em Python – Saiba como criar Superclasse e Subclasse
A herança em Python é um conceito essencial na programação orientada a objetos (POO), permitindo que uma classe (subclasse) herde atributos e métodos de outra classe (superclasse). Isso facilita a reutilização e a organização do código..
Se quiser pode acompanhar esse conteúdo em formato de vídeo ou pode acessar o nosso Canal do YouTube para mais vídeos!
Para receber por e-mail o(s) arquivo(s) utilizados na aula, preencha:
Não vamos te encaminhar nenhum tipo de SPAM! A Hashtag Treinamentos é uma empresa preocupada com a proteção de seus dados e realiza o tratamento de acordo com a Lei Geral de Proteção de Dados (Lei n. 13.709/18). Qualquer dúvida, nos contate.
O Que é Herança na POO?
A herança é um dos conceitos mais importantes da POO em Python. Ela permite a criação de novas classes (subclasses) a partir de uma classe existente (superclasse).
As subclasses herdam os atributos e métodos da superclasse, mas também podem incorporar funcionalidades exclusivas.
A herança permite uma melhor:
- Reutilização de código: Reduz a necessidade de duplicar funcionalidades comuns.
- Organização do código: Facilita a criação de hierarquias lógicas entre classes.
- Facilidade de expansão: Permite personalizar subclasses sem modificar a classe principal.
De forma simplificada, uma subclasse é uma versão especializada da superclasse. Utilizar a herança permite reutilizar e expandir o código de maneira eficiente, prática e organizada, contribuindo para um desenvolvimento mais ágil do seu programa.
Superclasse no Python
Para entendermos como o conceito de herança é aplicado no Python, vamos usar como exemplo o jogo FIFA, onde existem diversos jogadores que compartilham características comuns, mas também possuem habilidades específicas.
Por exemplo, todo jogador tem atributos básicos, como altura, velocidade, passe, drible e precisão. Além disso, independentemente da posição em campo, todo jogador pode passar e chutar a bola.
Essas características e métodos são a base para qualquer jogador no FIFA, independentemente de sua posição. No entanto, além dessas características compartilhadas, alguns jogadores possuem atributos e métodos específicos, como o goleiro, que é o único capaz de agarrar a bola.
Podemos, então, pensar na classe Jogador como a superclasse que definirá os atributos e métodos compartilhados por todos os jogadores.
class Jogador: def __init__(self, altura, velocidade, passe, drible, precisao): self.altura = altura self.velocidade = velocidade self.passe = passe self.drible = drible self.precisao = precisao def passar(self): print("Mirar") print("Encostar na bola com a força de passe do jogador") def chutar(self): print("Mirar") print("Encostar na bola com 2x a força de passe do jogador")
A partir dessa estrutura, podemos criar subclasses para definir os diferentes tipos de jogadores, como jogadores de linha e goleiros.
É aqui que entra a herança de classes. Em vez de redefinir manualmente os atributos e métodos compartilhados por todos os jogadores, as novas classes podem simplesmente herdar essas características da superclasse Jogador.
Subclasses no Python
Com a superclasse criada, podemos agora definir as subclasses Jogador_Goleiro e Jogador_Linha.
A subclasse Jogador_Goleiro terá um método próprio para agarrar a bola, enquanto a subclasse Jogador_Linha herdará apenas os atributos e métodos comuns da superclasse, sem habilidades especiais adicionais.
Para indicar ao Python que uma classe é filha (subclasse) de outra, basta passar o nome da classe mãe (superclasse) entre parênteses ao definir a nova classe.
A sintaxe class Subclasse(Superclasse) estabelece que a nova classe “estende” ou “herda” os comportamentos de outra.
class Jogador: def __init__(self, altura, velocidade, passe, drible, precisao): self.altura = altura self.velocidade = velocidade self.passe = passe self.drible = drible self.precisao = precisao def passar(self): print("Mirar") print("Encostar na bola com a força de passe do jogador") def chutar(self): print("Mirar") print("Encostar na bola com 2x a força de passe do jogador") class Jogador_Goleiro(Jogador): def agarrar(self): print("Pular") print("Se esticar para pegar a bola") class Jogador_Linha(Jogador): pass
No exemplo, a subclasse Jogador_Goleiro herdou todas as características da superclasse Jogador e ainda recebeu o método exclusivo agarrar().
Essa nova funcionalidade é específica da subclasse Jogador_Goleiro e não altera o comportamento da superclasse ou de outras subclasses, como Jogador_Linha.
Criando os Objetos e Testando a Herança de Classe
Com as classes prontas, o próximo passo é criar objetos e verificar, na prática, como a herança funciona.
Para criar esses jogadores, precisamos informar os atributos definidos no método __init__ da classe Jogador.
# Criando um goleiro e um jogador de linha jogador1 = Jogador_Goleiro(180, 60, 80, 20, 60) jogador2 = Jogador_Linha(174, 90, 80, 85, 80)
Feito isso, podemos testar os métodos herdados e específicos de cada objeto.
Goleiro:
jogador1.passar() # Método herdado jogador1.agarrar() # Método específico do goleiro
Jogador de Linha:
jogador2.passar() # Método herdado jogador2.agarrar() # Método específico do goleiro
Observe que ambos os jogadores conseguem executar o método passar(), que foi herdado da superclasse Jogador. Entretanto, somente o jogador1, criado a partir da classe Jogador_Goleiro, é capaz de usar o método agarrar(), que é exclusivo dessa subclasse.
Ao tentarmos executar o método agarrar() com o jogador2, recebemos um erro, pois essa funcionalidade não está definida na classe Jogador_Linha.
Polimorfismo em Python
Agora vamos falar de outro pilar fundamental da programação orientada a objetos (POO): o Polimorfismo!
Se quiser pode acompanhar esse conteúdo em formato de vídeo ou pode acessar o nosso Canal do YouTube para mais vídeos!
Para receber por e-mail o(s) arquivo(s) utilizados na aula, preencha:
Não vamos te encaminhar nenhum tipo de SPAM! A Hashtag Treinamentos é uma empresa preocupada com a proteção de seus dados e realiza o tratamento de acordo com a Lei Geral de Proteção de Dados (Lei n. 13.709/18). Qualquer dúvida, nos contate.
O que é o Polimorfismo em Python?
A palavra Polimorfismo vem do grego e significa “muitas formas”. Em termos de programação, esse conceito é um dos pilares da POO e permite que objetos diferentes respondam ao mesmo método de formas distintas.
Em Python, o polimorfismo geralmente é implementado com o uso de herança. A superclasse define os métodos gerais, que podem ser sobrescritos por subclasses, adaptando-os às necessidades específicas de cada uma.
Essa característica é especialmente útil para criar sistemas flexíveis e reutilizáveis.
Como o Polimorfismo Funciona?
Para visualizar o polimorfismo na prática, vamos continuar com o exemplo do FIFA que usamos para as heranças.
Dentro da superclasse Jogador, tínhamos os atributos altura, velocidade, passe, drible e precisao, além dos métodos passar e chutar. Agora, vamos adicionar o método defender.
class Jogador: def __init__(self, altura, velocidade, passe, drible, precisao): self.altura = altura self.velocidade = velocidade self.passe = passe self.drible = drible self.precisao = precisao def passar(self): print("Mirar") print("Encostar na bola com a força de passe do jogador") def chutar(self): print("Mirar") print("Encostar na bola com 2x a força de passe do jogador") def defender(self): print("Tentar tirar a bola do adversário")
A partir dessa superclasse, criamos as subclasses Jogador_Goleiro e Jogador_Linha, que herdam os métodos e atributos da classe Jogador.
No entanto, o método defender, apesar de ser herdado pelas duas, tem comportamentos diferentes para cada tipo de jogador. Por exemplo, o goleiro pode usar as mãos dentro da área ao defender, enquanto o jogador de linha só pode usar os pés, ombros e cabeça.
class Jogador_Goleiro(Jogador): def agarrar(self): print("Pular") print("Se esticar para pegar a bola") # Método herdado, mas alterado para o goleiro def defender(self): esta_fora_area = False if esta_fora_area: print("Usar apenas os pés, cabeça, ombro") else: print("Usar qualquer parte do corpo") print("Tentar tirar a bola do adversário") class Jogador_Linha(Jogador): # Método herdado, mas alterado para o jogador de linha def defender(self): print("Usar apenas os pés, cabeça, ombro") print("Tentar tirar a bola do adversário")
Essas diferenças no comportamento do mesmo método, em classes diferentes, é o que chamamos de polimorfismo.
Assim, quando criamos os objetos referentes ao goleiro e ao jogador de linha, e utilizamos o método defender(), cada um deles se comportará de forma específica para sua classe.
# Criando um goleiro e um jogador de linha jogador1 = Jogador_Goleiro(180, 60, 60, 50, 70) jogador2 = Jogador_Linha(179, 90, 80, 85, 90) # Usando o método defender print("Goleiro:") jogador1.defender() print("Linha:") jogador2.defender()
Isso permite que diferentes objetos realizem uma ação parecida, mas de forma específica para cada um. Usando essas etapas, você pode criar sistemas mais organizados e modulares.
Aplicando o Polimorfismo em Outras Situações
Aqui vimos um exemplo de como utilizar o polimorfismo com o exemplo de um jogo, mas ele pode ser aplicado a diferentes contextos, como sistemas de bancos e lojas.
Por exemplo, você pode ter uma classe Pagamento, representando os tipos de pagamento aceitos, e subclasses para cada tipo, como Cartao, Pix ou Dinheiro.
Cada subclasse processa o pagamento de uma maneira diferente, mas o comando para isso pode ser o mesmo método processar_pagamento().
Benefícios do Polimorfismo
- Reutilização de Código: Métodos comuns são implementados na superclasse, enquanto as diferenças específicas são tratadas nas subclasses.
- Flexibilidade: O mesmo método pode ser chamado em diferentes classes, sem a necessidade de se preocupar com implementações específicas.
- Manutenção Facilitada: Alterações em métodos da superclasse são refletidas automaticamente nas subclasses.
Conclusão – Classes no Python – Como Sair do Zero em POO
Nesta aula, você aprendeu desde os conceitos básicos até exemplos práticos da Programação Orientada a Objetos (POO) em Python. Vimos o que são e como criar classes no Python, instanciar objetos, definir atributos e métodos, além de validar dados.
A POO é essencial para desenvolver sistemas mais completos, organizados e reutilizáveis, facilitando a manutenção e escalabilidade do seu código. Ela permite que você crie soluções modulares, o que torna o desenvolvimento de projetos em Python mais eficiente e sustentável.
Continue praticando e exercitando esses conceitos. Crie suas próprias classes, modifique os exemplos apresentados e explore novos casos de uso. Com o tempo, você se sentirá mais confortável e habilidoso para aplicar a POO de forma criativa e eficaz.
Se você quiser dar o próximo passo e compreender ainda mais a fundo esses conceitos tão importantes para a programação, não deixe de conferir nossos minicursos gratuitos de criação de jogos e sites com Python!
Nesses minicursos, você aprenderá na prática como as classes são aplicadas em projetos completos, desenvolvidos com você desde o zero.
Hashtag Treinamentos
Para acessar outras publicações de Python, clique aqui!
Posts mais recentes de Python
- Biblioteca NumPy: o que é, vantagens e como usarAprenda como usar a biblioteca NumPy no Python para otimizar o processamento de dados e melhorar sua eficiência em projetos de ciência de dados.
- Set em Python: o que é, quando e como usar no seu projetoAprenda tudo sobre sets em Python: o que são, como usar e quando aplicar. Descubra operações com conjuntos e vantagens sobre listas!
- ETL com Python: guia completo para criar pipelines de dadosAprenda como construir pipelines ETL com Python do zero! Descubra as melhores bibliotecas, resolva desafios comuns e torne-se um especialista!
Posts mais recentes da Hashtag Treinamentos
- 5 Boas Práticas de SQL para Iniciantes: Otimize Suas Consultas e Organize Seu CódigoSe você está começando com MySQL ou busca melhorar suas habilidades em SQL, este post traz cinco boas práticas de escrita de SQL para iniciantes.
- Função SE Excel: Exemplos e Dicas para Uso [Guia]A função SE Excel é muito útil para definir condições e criar uma planilha mais completa e funcional. Confira nesta aula!
- Exercícios de Listening em Inglês – Como Melhorar sua CompreensãoFaça estes exercícios de listening em inglês e melhore sua compreensão! Descubra técnicas e estratégias para praticar e evoluir no aprendizado do idioma!
Expert em conteúdos da Hashtag Treinamentos. Auxilia na criação de conteúdos de variados temas voltados para aqueles que acompanham nossos canais.