Python

O que Todo Dev Deve Saber sobre Classes e Objetos em Python: Atributos, Métodos e __init__

13 min de leitura

O que Todo Dev Deve Saber sobre Classes e Objetos em Python: Atributos, Métodos e __init__

Entendendo Classes e Objetos: O Fundamento da Programação Orientada a Objetos Quando começamos a programar, frequentemente utilizamos variáveis simples e funções soltas para resolver problemas. No entanto, quando os projetos crescem e a complexidade aumenta, essa abordagem se torna caótica e difícil de manter. Classes e objetos são a resposta que a Programação Orientada a Objetos (POO) oferece para organizar código de forma estruturada, reutilizável e intuitiva. Uma classe é um molde ou blueprint que define como um objeto deve ser estruturado. Um objeto é uma instância concreta dessa classe — é o resultado de usar esse molde. Pense em uma classe como a receita de um bolo e o objeto como o bolo propriamente dito. Você pode fazer vários bolos usando a mesma receita, cada um com suas características particulares. Em Python, as classes nos permitem encapsular dados (atributos) e comportamentos (métodos) em uma unidade coesa que modela entidades do mundo real. A Estrutura Básica: Definindo Uma Classe Criando

<h2>Entendendo Classes e Objetos: O Fundamento da Programação Orientada a Objetos</h2>

<p>Quando começamos a programar, frequentemente utilizamos variáveis simples e funções soltas para resolver problemas. No entanto, quando os projetos crescem e a complexidade aumenta, essa abordagem se torna caótica e difícil de manter. Classes e objetos são a resposta que a Programação Orientada a Objetos (POO) oferece para organizar código de forma estruturada, reutilizável e intuitiva.</p>

<p>Uma <strong>classe</strong> é um molde ou blueprint que define como um objeto deve ser estruturado. Um <strong>objeto</strong> é uma instância concreta dessa classe — é o resultado de usar esse molde. Pense em uma classe como a receita de um bolo e o objeto como o bolo propriamente dito. Você pode fazer vários bolos usando a mesma receita, cada um com suas características particulares. Em Python, as classes nos permitem encapsular dados (atributos) e comportamentos (métodos) em uma unidade coesa que modela entidades do mundo real.</p>

<h2>A Estrutura Básica: Definindo Uma Classe</h2>

<h3>Criando sua primeira classe</h3>

<p>Uma classe em Python é definida usando a palavra-chave <code>class</code>. A estrutura mais básica segue este padrão:</p>

<pre><code class="language-python">class Pessoa:

pass</code></pre>

<p>Isso cria uma classe vazia. Para que ela seja útil, precisamos adicionar atributos e métodos. Os atributos são características (dados) e os métodos são ações (funções) que a classe pode executar.</p>

<pre><code class="language-python">class Carro:

def __init__(self, marca, modelo, ano):

self.marca = marca

self.modelo = modelo

self.ano = ano

def descrever(self):

return f&quot;{self.ano} {self.marca} {self.modelo}&quot;

def idade(self, ano_atual=2024):

return ano_atual - self.ano</code></pre>

<p>Agora vamos criar instâncias dessa classe:</p>

<pre><code class="language-python">carro1 = Carro(&quot;Toyota&quot;, &quot;Corolla&quot;, 2020)

carro2 = Carro(&quot;Honda&quot;, &quot;Civic&quot;, 2018)

print(carro1.descrever()) # 2020 Toyota Corolla

print(carro2.idade()) # 6</code></pre>

<h3>O papel crucial do método <code>__init__</code></h3>

<p>O método <code>__init__</code> é o <strong>construtor</strong> da classe — ele é automaticamente chamado quando você cria uma nova instância. Seu principal objetivo é inicializar os atributos do objeto com valores específicos passados como argumentos. Sem <code>__init__</code>, você teria que atribuir manualmente cada atributo após criar o objeto, o que seria trabalhoso e propenso a erros.</p>

<p>O primeiro parâmetro de qualquer método, incluindo <code>__init__</code>, é sempre <code>self</code>. Esse parâmetro especial representa a instância do objeto em questão. Quando você escreve <code>self.marca = marca</code>, está dizendo: &quot;no objeto que estou criando, defina o atributo &#039;marca&#039; com o valor passado como argumento&quot;.</p>

<pre><code class="language-python">class Produto:

def __init__(self, nome, preco, estoque=0):

self.nome = nome

self.preco = preco

self.estoque = estoque

self.desconto = 0 # Atributo com valor padrão

produto1 = Produto(&quot;Notebook&quot;, 3500.00, 5)

produto2 = Produto(&quot;Mouse&quot;, 50.00) # estoque não fornecido, usa padrão

print(f&quot;{produto1.nome}: R$ {produto1.preco}&quot;)

print(f&quot;Estoque de {produto2.nome}: {produto2.estoque}&quot;)</code></pre>

<h2>Atributos: Armazenando Dados no Objeto</h2>

<h3>Atributos de instância versus atributos de classe</h3>

<p>Existem dois tipos de atributos em Python. Os <strong>atributos de instância</strong> são específicos de cada objeto e são definidos dentro de <code>__init__</code>. Os <strong>atributos de classe</strong> pertencem à classe como um todo e são compartilhados por todas as instâncias.</p>

<pre><code class="language-python">class Conta:

juros = 0.05 # Atributo de classe - compartilhado por todas as contas

def __init__(self, titular, saldo=0):

self.titular = titular # Atributo de instância

self.saldo = saldo # Atributo de instância

conta1 = Conta(&quot;Alice&quot;, 1000)

conta2 = Conta(&quot;Bob&quot;, 2000)

print(conta1.titular) # Alice

print(conta1.saldo) # 1000

print(Conta.juros) # 0.05 - acessado pela classe

Cada instância tem seus próprios atributos de instância

print(conta1.juros) # 0.05 - acessa via instância

print(conta2.juros) # 0.05 - mesmo valor</code></pre>

<h3>Modificando atributos após a criação</h3>

<p>Os atributos não são imutáveis após a criação. Você pode modificá-los a qualquer momento:</p>

<pre><code class="language-python">class Estudante:

def __init__(self, nome, matricula):

self.nome = nome

self.matricula = matricula

self.notas = []

def adicionar_nota(self, nota):

self.notas.append(nota)

def media(self):

return sum(self.notas) / len(self.notas) if self.notas else 0

aluno = Estudante(&quot;Carlos&quot;, &quot;2024001&quot;)

aluno.adicionar_nota(7.5)

aluno.adicionar_nota(8.0)

aluno.adicionar_nota(9.5)

print(f&quot;Média de {aluno.nome}: {aluno.media():.2f}&quot;) # 8.33</code></pre>

<h2>Métodos: Definindo Comportamentos</h2>

<h3>O que são métodos e como funcionam</h3>

<p>Um método é uma função definida dentro de uma classe. Ele permite que objetos realizem ações e modifiquem seus próprios dados. Todo método recebe <code>self</code> como primeiro parâmetro, permitindo acesso aos atributos e outros métodos da instância.</p>

<pre><code class="language-python">class Banco:

def __init__(self, saldo_inicial=0):

self.saldo = saldo_inicial

def depositar(self, valor):

&quot;&quot;&quot;Adiciona valor ao saldo&quot;&quot;&quot;

if valor &gt; 0:

self.saldo += valor

return f&quot;Depósito de R$ {valor:.2f} realizado. Saldo: R$ {self.saldo:.2f}&quot;

return &quot;Valor deve ser positivo&quot;

def sacar(self, valor):

&quot;&quot;&quot;Remove valor do saldo se houver fundos&quot;&quot;&quot;

if valor &gt; self.saldo:

return f&quot;Saldo insuficiente. Disponível: R$ {self.saldo:.2f}&quot;

if valor &gt; 0:

self.saldo -= valor

return f&quot;Saque de R$ {valor:.2f} realizado. Saldo: R$ {self.saldo:.2f}&quot;

return &quot;Valor deve ser positivo&quot;

def obter_saldo(self):

&quot;&quot;&quot;Retorna o saldo atual&quot;&quot;&quot;

return self.saldo

conta = Banco(500)

print(conta.depositar(200)) # Depósito de R$ 200.00 realizado. Saldo: R$ 700.00

print(conta.sacar(150)) # Saque de R$ 150.00 realizado. Saldo: R$ 550.00

print(f&quot;Saldo final: R$ {conta.obter_saldo():.2f}&quot;)</code></pre>

<h3>Métodos especiais em Python</h3>

<p>Python oferece vários métodos especiais (dunder methods) que começam e terminam com dois underscores. Eles permitem que seus objetos se comportem como objetos nativos do Python. Alguns dos mais importantes são:</p>

<pre><code class="language-python">class Livro:

def __init__(self, titulo, autor, paginas):

self.titulo = titulo

self.autor = autor

self.paginas = paginas

def __str__(self):

&quot;&quot;&quot;Retorna representação legível para humanos&quot;&quot;&quot;

return f&quot;{self.titulo} por {self.autor}&quot;

def __repr__(self):

&quot;&quot;&quot;Retorna representação técnica (útil para debug)&quot;&quot;&quot;

return f&quot;Livro(&#039;{self.titulo}&#039;, &#039;{self.autor}&#039;, {self.paginas})&quot;

def __len__(self):

&quot;&quot;&quot;Permite usar len() no objeto&quot;&quot;&quot;

return self.paginas

def __eq__(self, outro):

&quot;&quot;&quot;Permite comparar dois livros com ==&quot;&quot;&quot;

if not isinstance(outro, Livro):

return False

return self.titulo == outro.titulo and self.autor == outro.autor

livro1 = Livro(&quot;1984&quot;, &quot;George Orwell&quot;, 328)

livro2 = Livro(&quot;1984&quot;, &quot;George Orwell&quot;, 328)

print(str(livro1)) # 1984 por George Orwell

print(repr(livro1)) # Livro(&#039;1984&#039;, &#039;George Orwell&#039;, 328)

print(len(livro1)) # 328

print(livro1 == livro2) # True</code></pre>

<h2>Boas Práticas e Padrões Comuns</h2>

<h3>Encapsulamento com atributos privados</h3>

<p>Em Python, não existe encapsulamento forçado como em outras linguagens, mas usa-se a convenção de prefixar nomes com underscore para indicar que um atributo é &quot;privado&quot; (não deve ser acessado diretamente de fora):</p>

<pre><code class="language-python">class Senha:

def __init__(self, valor):

self._valor = valor # Convenção: privado

def validar(self, tentativa):

return self._valor == tentativa

def mudar(self, antiga, nova):

if self._valor == antiga:

self._valor = nova

return &quot;Senha alterada com sucesso&quot;

return &quot;Senha antiga incorreta&quot;

conta = Senha(&quot;minhasenha123&quot;)

print(conta.validar(&quot;minhasenha123&quot;)) # True

print(conta.mudar(&quot;minhasenha123&quot;, &quot;nova&quot;)) # Senha alterada com sucesso</code></pre>

<h3>Usando propriedades (properties) para controle de acesso</h3>

<p>Para mais controle sobre como os atributos são acessados e modificados, use o decorador <code>@property</code>:</p>

<pre><code class="language-python">class Temperatura:

def __init__(self, celsius=0):

self._celsius = celsius

@property

def celsius(self):

&quot;&quot;&quot;Getter para celsius&quot;&quot;&quot;

return self._celsius

@celsius.setter

def celsius(self, valor):

&quot;&quot;&quot;Setter com validação&quot;&quot;&quot;

if valor &lt; -273.15:

raise ValueError(&quot;Temperatura abaixo do zero absoluto&quot;)

self._celsius = valor

@property

def fahrenheit(self):

&quot;&quot;&quot;Propriedade calculada&quot;&quot;&quot;

return (self._celsius * 9/5) + 32

temp = Temperatura(25)

print(f&quot;{temp.celsius}°C = {temp.fahrenheit}°F&quot;) # 25°C = 77.0°F

temp.celsius = 0

print(f&quot;{temp.celsius}°C = {temp.fahrenheit}°F&quot;) # 0°C = 32.0°F</code></pre>

<h3>Um exemplo prático completo</h3>

<p>Vamos criar uma classe que demonstra todos os conceitos aprendidos:</p>

<pre><code class="language-python">class Funcionario:

Atributo de classe

empresa = &quot;TechCorp&quot;

salario_minimo = 1200

def __init__(self, nome, cargo, salario):

self.nome = nome

self.cargo = cargo

self._salario = salario

self.horas_trabalhadas = 0

@property

def salario(self):

return self._salario

@salario.setter

def salario(self, valor):

if valor &lt; self.salario_minimo:

raise ValueError(f&quot;Salário não pode ser menor que R$ {self.salario_minimo}&quot;)

self._salario = valor

def registrar_hora(self, horas):

self.horas_trabalhadas += horas

return f&quot;{self.nome} registrou {horas} horas&quot;

def calcular_bonus(self):

if self.horas_trabalhadas &gt; 160:

return self._salario * 0.10

return 0

def __str__(self):

return f&quot;{self.nome} - {self.cargo} (R$ {self._salario:.2f})&quot;

def __repr__(self):

return f&quot;Funcionario(&#039;{self.nome}&#039;, &#039;{self.cargo}&#039;, {self._salario})&quot;

Criando instâncias

func1 = Funcionario(&quot;Ana&quot;, &quot;Desenvolvedora&quot;, 5000)

func2 = Funcionario(&quot;Bruno&quot;, &quot;Designer&quot;, 3500)

print(func1) # Ana - Desenvolvedora (R$ 5000.00)

print(func1.registrar_hora(40)) # Ana registrou 40 horas

print(f&quot;Bônus: R$ {func1.calcular_bonus():.2f}&quot;)

Tentando alterar salário

try:

func2.salario = 800 # Vai lançar exceção

except ValueError as e:

print(f&quot;Erro: {e}&quot;)</code></pre>

<h2>Conclusão</h2>

<p>Nesta aula, você compreendeu que <strong>classes e objetos são a base da Programação Orientada a Objetos em Python</strong>, permitindo modelar entidades do mundo real de forma intuitiva e organizada. O método <code>__init__</code> é o construtor que inicializa seus objetos, eliminando a necessidade de configuração manual após instanciação — isso torna o código mais limpo e seguro. Finalmente, atributos e métodos trabalham juntos para encapsular dados e comportamentos, criando abstrações poderosas que facilitam manutenção, reutilização e escalabilidade de código.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://docs.python.org/3/tutorial/classes.html" target="_blank" rel="noopener noreferrer">Python Official Documentation - Classes</a></li>

<li><a href="https://realpython.com/python3-object-oriented-programming/" target="_blank" rel="noopener noreferrer">Real Python - Object-Oriented Programming</a></li>

<li><a href="https://www.w3schools.com/python/python_oop.asp" target="_blank" rel="noopener noreferrer">W3Schools - Python OOP</a></li>

<li><a href="https://automatetheboringstuff.com/2e/chapter12/" target="_blank" rel="noopener noreferrer">Automate the Boring Stuff with Python - Chapter 12: OOP</a></li>

<li><a href="https://pep8.org/" target="_blank" rel="noopener noreferrer">PEP 8 - Style Guide for Python Code</a></li>

</ul>

<p>&lt;!-- FIM --&gt;</p>

Comentários

Mais em Python

SQLAlchemy Core em Python: Conexão, Queries e Transactions na Prática
SQLAlchemy Core em Python: Conexão, Queries e Transactions na Prática

Introdução ao SQLAlchemy Core SQLAlchemy é a biblioteca SQL mais madura e rob...

Boas Práticas de MongoDB com Python: pymongo, Motor Assíncrono e Aggregation para Times Ágeis
Boas Práticas de MongoDB com Python: pymongo, Motor Assíncrono e Aggregation para Times Ágeis

Introdução ao MongoDB e PyMongo MongoDB é um banco de dados NoSQL orientado a...

Tipos Avançados em Python: Generic, Protocol, TypeVar e ParamSpec na Prática
Tipos Avançados em Python: Generic, Protocol, TypeVar e ParamSpec na Prática

Introdução aos Tipos Avançados em Python Python é uma linguagem dinamicamente...