Módulo 10 - Orientação a objetos avançada
property: getter, setter e validação
10 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026
O que você vai aprender
- Entender o problema de expor um atributo sem controle.
- Criar um getter com @property.
- Criar um setter com validação usando @nome.setter.
- Manter a interface obj.valor mesmo com lógica por trás.
Ouvir o resumo desta aula
Um recap de cerca de 2 minutos na voz do Valim, para ouvir no trânsito ou na academia.
Ler a transcrição do resumo
Resumo da aula: property: getter, setter e validação.
Os objetivos desta aula. Entender o problema de expor um atributo sem controle. Criar um getter com @property. Criar um setter com validação usando @nome.setter. Manter a interface obj.valor mesmo com lógica por trás.
Veja o essencial, parte por parte.
O problema do atributo livre. Um atributo público comum aceita qualquer valor, inclusive inválido.
O getter com @property. Guarde o valor real em um atributo com sublinhado, como _raio, e exponha a property com o nome limpo.
O setter que valida. O poder de verdade aparece no setter.
Esse foi o resumo do essencial. Para se aprofundar, leia a aula completa e responda os exercícios.
O problema do atributo livre
Imagine uma classe Produto com um atributo preco. Se ele for um campo público comum, nada impede alguém de escrever produto.preco = -50, e agora o seu sistema tem um produto de preço negativo. Em muitas linguagens, a saída seria esconder o campo e obrigar todo mundo a usar métodos getPreco e setPreco, com a validação dentro do set. Funciona, mas é verboso: quem usa a classe precisa chamar métodos toda vez, e o código fica cheio de parênteses. O Python resolve isso de um jeito mais elegante, sem sacrificar a simplicidade de escrever produto.preco.
A ideia da property é começar simples e só adicionar controle quando precisar, sem quebrar quem já usa a classe. Você pode lançar uma classe com um atributo público comum e, no dia em que surgir a necessidade de validar, transformá-lo em property sem mudar uma linha do código que a consome. A interface externa continua idêntica, produto.preco para ler e produto.preco = 10 para escrever, mas agora há funções suas rodando por trás. Esse é o encapsulamento à moda do Python: cobre a lógica quando ela é necessária, sem cerimônia antecipada.
O getter com @property
O primeiro passo é o getter. Você escreve um método com o nome do atributo e o decora com @property. A partir daí, ao ler obj.preco, o Python chama esse método em vez de devolver um campo. Por convenção, o valor real fica guardado em um atributo com um sublinhado na frente, como _preco, sinalizando que é interno. Repare que quem usa a classe nem percebe: escreve produto.preco, sem parênteses, exatamente como faria com um campo comum. A property também é ótima para valores calculados, que derivam de outros atributos e não precisam ser guardados.
class Circulo:
def __init__(self, raio):
self._raio = raio
@property
def raio(self):
return self._raio
@property
def area(self): # valor calculado, sem campo proprio
return 3.14159 * self._raio ** 2
c = Circulo(2)
print(c.raio) # 2 (chamou o getter, sem parenteses)
print(c.area) # 12.56636 (calculado na hora)@property faz raio e area serem lidos como atributos; area é calculada a cada acesso.
O setter que valida
O poder de verdade aparece no setter. Depois de definir o getter com @property, você cria um segundo método com o mesmo nome do atributo, decorado com @nome.setter, e é ali que a validação mora. Toda vez que alguém escrever produto.preco = valor, o Python chamará esse método, passando o valor. Se ele for inválido, você levanta uma exceção e a atribuição errada nunca acontece. O resultado é uma classe que se defende: é impossível colocá-la em um estado inconsistente pela porta da frente, e mesmo assim a sintaxe de uso permanece a de um campo comum.
class Produto:
def __init__(self, preco):
self.preco = preco # ja passa pelo setter e valida
@property
def preco(self):
return self._preco
@preco.setter
def preco(self, valor):
if not isinstance(valor, (int, float)):
raise TypeError("preco deve ser numero")
if valor < 0:
raise ValueError("preco nao pode ser negativo")
self._preco = valor
p = Produto(10)
p.preco = 25 # ok, passa na validacao
print(p.preco) # 25
# p.preco = -5 # ValueError: preco nao pode ser negativoO setter valida a cada atribuição; até o __init__ usa self.preco para passar pela validação.
Um detalhe elegante do exemplo: o __init__ atribui self.preco = preco, e não self._preco = preco. Com isso, até a criação do objeto passa pela validação do setter, então nem no construtor um valor inválido escapa. Essa é a marca de uma classe bem projetada no avançado: ela garante suas próprias invariantes, aquelas regras que precisam ser sempre verdadeiras, como preço não negativo. A property centraliza essa garantia em um único lugar, em vez de espalhar validações por todo o código que mexe no objeto.
Teste rápido
Qual a principal vantagem de usar @property com setter em vez de deixar o atributo público?
Perguntas frequentes
- Devo transformar todo atributo em property desde o início?
- Não. A filosofia pythônica é começar com atributos públicos simples e só criar property quando surgir a necessidade de validar ou calcular. Como a interface de acesso não muda, você pode fazer essa transformação depois, sem quebrar o código que já usa a classe. Encapsular cedo demais só adiciona ruído.
- O sublinhado em _preco torna o atributo privado de verdade?
- Não no sentido de outras linguagens. O sublinhado é uma convenção que sinaliza uso interno; o Python não impede o acesso. A property é o que dá controle real, interceptando leitura e escrita. O sublinhado apenas comunica a intenção de que _preco é detalhe interno, não parte da interface.
- Uma property sem setter serve para quê?
- Vira um atributo somente leitura: dá para ler obj.valor, mas tentar atribuir levanta erro. É útil para valores calculados, como a área de um círculo, ou para expor um dado interno que não deve ser alterado de fora. Você adiciona o setter só se e quando a escrita fizer sentido.
- Posso ter validação diferente na leitura e na escrita?
- Sim. O getter e o setter são métodos separados, cada um com sua lógica. O getter pode formatar ou calcular o valor devolvido, e o setter pode validar ou transformar o valor recebido. Essa separação é justamente a vantagem de interceptar as duas operações de forma independente.
- Property tem custo de desempenho?
- Cada acesso vira uma chamada de método, o que é um pouco mais caro que ler um campo direto, mas o custo é pequeno e raramente relevante. Só se torna algo a considerar em laços muito quentes, e mesmo assim a clareza e a segurança que a property traz costumam compensar. Meça antes de otimizar.
Fontes
Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.