Python Classes e Objetos
Até aqui você guardou cada informação numa variável solta: nome = "Café", preco = 18.90, estoque = 12. Com um produto, tudo bem. Com os 40 produtos da lojinha da Ana, começa a bagunça: qual preço é de qual produto? A classe resolve isso. Ela é um modelo que diz como uma coisa é feita ("todo produto tem nome e preço"), e a partir dela você cria quantas coisas quiser, cada uma com os seus próprios dados. Cada coisa criada a partir da classe se chama objeto. Esta aula abre o capítulo de Orientação a Objetos: o jeito de programar em que o programa é feito de objetos que guardam dados e sabem fazer coisas.
- A diferença entre classe (o modelo) e objeto (a coisa feita a partir do modelo).
- A criar uma classe com
classe um objeto comProduto(). - O que quer dizer
<__main__.Produto object at 0x7f…>, e por que esse número muda. - A pendurar dados num objeto (os atributos) e a lê-los com o ponto:
cafe.nome. - A perguntar de que classe é um objeto, com
type()eisinstance(). - Os erros reais:
AttributeError,IndentationError,NameErrore o parêntese esquecido, que não dá erro nenhum.
A ideia: a forma e os bolos
Pense numa forma de bolo. A forma não é um bolo: você não come a forma. Ela é o modelo que dá o formato. Com a mesma forma, a padaria do bairro faz um bolo de chocolate, um de cenoura e um de laranja. Os três têm o mesmo formato, mas cada um é um bolo diferente, com o seu próprio sabor. Se alguém come um pedaço do bolo de cenoura, o de chocolate continua inteiro.
Outra comparação: a ficha de cadastro em branco da lojinha. Ela diz quais campos todo produto tem (nome, preço, estoque). Cada produto cadastrado é uma ficha preenchida, uma cópia da ficha em branco com os dados daquele produto.
| No dia a dia | Em Python | Exemplo |
|---|---|---|
| A forma de bolo, a ficha em branco | A classe | Produto |
| Cada bolo, cada ficha preenchida | Um objeto (também chamado de instância da classe) | cafe, pao |
| Os campos da ficha (nome, preço) | Os atributos do objeto | cafe.nome, cafe.preco |
| Fazer um bolo com a forma | Criar um objeto (instanciar) | Produto() |
"Instância" é a palavra que os programadores usam para "objeto feito a partir de uma classe". cafe é uma instância de Produto: as duas frases querem dizer a mesma coisa.
1. Você já usa objetos desde a primeira aula
Em Python, tudo é objeto: textos, números, listas. Cada um deles foi feito a partir de uma classe que já vem pronta com o Python. A função type() mostra qual é:
nome = "ana" print(type(nome)) print(nome.upper()) print(type(42)) print(type([1, 2]))
$ python3 ja_conhece.py <class 'str'> ANA <class 'int'> <class 'list'>
<class 'str'> quer dizer: o texto "ana" é um objeto da classe str (de string, "texto"). E o .upper() que você usou na aula Métodos de Texto é uma coisa que todo objeto str sabe fazer. Até agora você só usou classes que outras pessoas escreveram. Nesta aula você vai escrever a sua.
2. A classe mais simples
class Produto:
pass
cafe = Produto()
print(cafe)
print(type(cafe))
- class
- A palavra-chave que cria uma classe (em inglês, "classe", no sentido de "categoria, tipo de coisa").
- Produto
- O nome da classe. Por costume, nomes de classe começam com letra maiúscula e, se tiverem mais de uma palavra, cada uma começa com maiúscula, sem sublinhado:
Produto,ContaBancaria,ItemDoPedido. É o jeito de saber, só de olhar, que aquele nome é uma classe. - :
- Os dois-pontos abrem o bloco da classe, como no
ife nodef. - pass
- "Passar", não fazer nada. O bloco da classe não pode ficar vazio, e por enquanto não temos nada para pôr nele. O
passocupa o lugar. - cafe = Produto()
- O nome da classe seguido de parênteses cria um objeto novo (usa a forma para fazer um bolo). O objeto é guardado na variável
cafe. - print(cafe)
- Mostra o objeto. Como ainda não ensinamos o Python a mostrar um
Produtode um jeito bonito, ele mostra do jeito padrão.
As duas linhas em branco depois da classe não são obrigatórias, mas são o costume (o guia de estilo do Python, a PEP 8, pede duas linhas em branco em volta de uma classe). Elas separam o modelo do código que o usa.
$ python3 produto.py <__main__.Produto object at 0x7f7351990590> <class '__main__.Produto'>
Lendo o <__main__.Produto object at 0x7f7351990590>
- < >
- Os sinais de menor e maior avisam: "isto não é um texto que você escreveu, é uma descrição do objeto".
- __main__
- Onde a classe foi criada.
__main__("principal") é o nome que o Python dá ao arquivo que você mandou rodar. Se a classe viesse de outro módulo, apareceria o nome dele. - Produto object
- "Objeto da classe Produto".
- at 0x7f7351990590
- "No endereço 0x7f7351990590": o lugar da memória do computador onde esse objeto está guardado, escrito em hexadecimal (o
0xavisa que o número está na base 16).
Rode o mesmo programa de novo e veja o endereço:
$ python3 produto.py <__main__.Produto object at 0x7f8bdaf90590> <class '__main__.Produto'>
Mudou. A cada execução, o Python guarda o objeto num lugar diferente da memória. Por isso, quando você rodar esses exemplos no seu computador (ou no editor do guia), vai ver outro número. (No editor do guia, que roda o Python dentro do navegador, o número costuma ser mais curto, como 0x1734f78, e também muda de um Rodar para o outro.) Não se preocupe com ele: o endereço não diz nada sobre o produto, só onde ele está. Na aula Métodos Especiais, você vai ensinar o Python a mostrar Produto: Café no lugar dessa descrição.
A segunda linha, <class '__main__.Produto'>, é o type(cafe): o objeto cafe é da classe Produto, criada no __main__. Repare que é o mesmo formato do <class 'str'> lá de cima: a sua classe é um tipo, igualzinho aos que já vêm com o Python.
3. Uma forma, vários bolos
Com a mesma classe, você cria quantos objetos quiser. Cada chamada Produto() faz um objeto novo:
class Produto:
pass
cafe = Produto()
pao = Produto()
print(cafe)
print(pao)
print(cafe is pao)
$ python3 dois_objetos.py <__main__.Produto object at 0x7f99bc530590> <__main__.Produto object at 0x7f99bc518690> False
Dois endereços diferentes: são dois objetos diferentes, guardados em lugares diferentes. O is (aula is e in) pergunta "é o mesmo objeto?", e a resposta é False. São dois bolos da mesma forma, não o mesmo bolo.
4. Atributos: os dados de cada objeto
Um objeto vazio não serve para muita coisa. Para guardar dados nele, use o ponto: objeto.nome_do_dado = valor. Cada dado guardado assim se chama atributo do objeto.
class Produto:
pass
cafe = Produto()
cafe.nome = "Café"
cafe.preco = 18.90
pao = Produto()
pao.nome = "Pão de forma"
pao.preco = 9.50
print(cafe.nome, cafe.preco)
print(pao.nome, pao.preco)
cafe.preco = 21.00
print(cafe.nome, cafe.preco)
print(pao.nome, pao.preco)
- cafe.nome = "Café"
- Cria, dentro do objeto
cafe, um atributo chamadonomecom o valor"Café". Leia o ponto como "de": "o nome do café recebe Café". - pao.nome = "Pão de forma"
- O objeto
paotem o seu próprionome. Os dois atributos têm o mesmo nome, mas moram em objetos diferentes. - print(cafe.nome, cafe.preco)
- Para ler um atributo, também se usa o ponto.
- cafe.preco = 21.00
- Um atributo funciona como uma variável: dá para trocar o valor. O preço do café subiu.
$ python3 atributos.py Café 18.9 Pão de forma 9.5 Café 21.0 « o preço do café mudou… Pão de forma 9.5 « …e o do pão continua o mesmo
Mudar o preço do café não mexeu no pão: cada objeto guarda os seus dados. É o bolo de cenoura que perdeu um pedaço, enquanto o de chocolate continua inteiro. (O 18.90 aparece como 18.9 porque o print não mostra o zero do fim; para mostrar 18.90, use uma f-string com :.2f, como na aula f-strings.)
No modo interativo dá para ver o objeto por dentro com a função vars(), que mostra os atributos dele como um dicionário:
$ python3 -q
>>> class Produto:
... pass
...
>>> cafe = Produto()
>>> cafe
<__main__.Produto object at 0x7f4e131ff0e0>
>>> cafe.nome = "Café"
>>> cafe.nome
'Café'
>>> vars(cafe)
{'nome': 'Café'}
>>> exit()
(O -q, de quiet, "quieto", só esconde a mensagem de boas-vindas do Python.) Por dentro, os atributos de um objeto ficam guardados num dicionário: o nome do atributo é a chave.
Missão: a lojinha começou a vender leite. Crie mais um objeto Produto, guardado na variável leite, com o nome "Leite" e o preço 6.50, e mostre os dois com print(leite.nome, leite.preco).
class Produto:
pass
cafe = Produto()
cafe.nome = "Café"
cafe.preco = 18.90
print(cafe.nome, cafe.preco)
# crie aqui o leite
class Produto:
pass
cafe = Produto()
cafe.nome = "Café"
cafe.preco = 18.90
print(cafe.nome, cafe.preco)
leite = Produto()
leite.nome = "Leite"
leite.preco = 6.50
print(leite.nome, leite.preco)
Pendurar os atributos um por um, depois de criar o objeto, funciona, mas é trabalhoso e perigoso: é fácil esquecer um. A ficha em branco de verdade já diz quais campos todo produto tem. Em Python, quem faz isso é o __init__, assunto da próxima aula: __init__ e self. Lá, criar um produto vira uma linha só: Produto("Café", 18.90).
5. De que classe é este objeto?
Duas formas de perguntar: type() diz qual é a classe; isinstance() ("é instância de?") responde True ou False.
class Produto:
pass
class Aluno:
pass
cafe = Produto()
print(isinstance(cafe, Produto))
print(isinstance(cafe, Aluno))
print(type(cafe) == Produto)
print(type(cafe).__name__)
$ python3 isinst.py True False True Produto
- isinstance(cafe, Produto)
- "O
cafeé umProduto?" Sim:True. - isinstance(cafe, Aluno)
- "O
cafeé umAluno?" Não:False. Um programa pode ter várias classes, cada uma com o seu nome. - type(cafe) == Produto
- Compara a classe do objeto com
Produto. Também dáTrue. - type(cafe).__name__
- Só o nome da classe, como texto:
Produto.
Para perguntar "é um produto?", prefira o isinstance(). Na aula Herança você vai ver por quê: ele também aceita as classes "filhas" de Produto, e o type() == não.
Formas diferentes de escrever a mesma classe
Você vai encontrar classes escritas de três jeitos em códigos e tutoriais pela internet:
class Produto:
pass
class Aluno():
pass
class Animal(object):
pass
print(Produto, Aluno, Animal)
print(Produto.__bases__, Aluno.__bases__, Animal.__bases__)
$ python3 formas.py <class '__main__.Produto'> <class '__main__.Aluno'> <class '__main__.Animal'> (<class 'object'>,) (<class 'object'>,) (<class 'object'>,)
As três dão no mesmo. O __bases__ mostra de quem a classe "herda": nas três, é de object, a classe-mãe de todas as classes do Python. Escrever (object) era necessário no Python 2, que acabou em 2020; no Python 3, toda classe herda de object sozinha. Os parênteses depois do nome da classe servem para a herança, assunto da aula Herança.
| Forma | Quando usar |
|---|---|
class Produto: | Sempre que a classe não herda de outra. É a forma do guia e a mais comum hoje |
class Produto(): | Funciona, mas os parênteses vazios não acrescentam nada. Evite |
class Produto(object): | Costume do Python 2. Funciona, mas no Python 3 é desnecessário. Você vai ver em códigos antigos |
Quando dá errado
AttributeError
class Produto:
pass
cafe = Produto()
cafe.nome = "Café"
print(cafe.nome)
print(cafe.preco)
$ python3 sem_atributo.py
Café
Traceback (most recent call last):
File "/home/ana/sem_atributo.py", line 8, in <module>
print(cafe.preco)
^^^^^^^^^^
AttributeError: 'Produto' object has no attribute 'preco'
Linha por linha:
Café: a linha 7 funcionou; onomeexiste.Traceback (most recent call last):"rastro, a chamada mais recente por último": começa o relatório do erro.File "/home/ana/sem_atributo.py", line 8, in <module>: o erro foi no arquivosem_atributo.py, na linha 8, no corpo principal do programa (<module>).print(cafe.preco)e os^^^^^^^^^^: a linha culpada, com o pedaço exato sublinhado:cafe.preco.AttributeError: 'Produto' object has no attribute 'preco': "erro de atributo: o objetoProdutonão tem o atributopreco".
Ninguém escreveu cafe.preco = …, então o café não tem preço. Um nome digitado errado (cafe.prego) dá o mesmo erro. Como consertar: crie o atributo antes de lê-lo, ou corrija o nome. (O __init__ da próxima aula evita esse erro: com ele, todo produto já nasce com nome e preço.)
Produto no lugar de Produto()
Esse erro não dá mensagem nenhuma, e é por isso que é perigoso:
class Produto:
pass
cafe = Produto
pao = Produto
cafe.nome = "Café"
print(pao.nome)
print(cafe)
$ python3 sem_parenteses.py Café « o pão se chama Café?! <class '__main__.Produto'> « cafe não é um objeto: é a própria classe
Sem os parênteses, cafe = Produto não cria bolo nenhum: só dá um segundo nome para a forma. cafe e pao viraram dois apelidos da própria classe Produto. Aí o cafe.nome = "Café" escreveu o nome na forma, e todo mundo que olha para a forma enxerga esse nome, inclusive o "pão". O print(cafe) entrega o problema: aparece <class …>, e não <… object at 0x…>. Como consertar: cafe = Produto(), com parênteses. Os parênteses são o "faça um objeto".
IndentationError
class Produto: cafe = Produto()
$ python3 sem_pass.py
File "/home/ana/sem_pass.py", line 3
cafe = Produto()
^^^^
IndentationError: expected an indented block after class definition on line 1
"Erro de indentação: era esperado um bloco recuado depois da definição de classe da linha 1". Depois dos dois-pontos, o Python espera pelo menos uma linha recuada, e encontrou o cafe encostado na margem. Repare que não há a linha Traceback: o Python nem começou a rodar, porque o arquivo está mal escrito. Como consertar: ponha um pass (recuado com 4 espaços) dentro da classe.
SyntaxError
class Produto
pass
$ python3 sem_dois_pontos.py
File "/home/ana/sem_dois_pontos.py", line 1
class Produto
^
SyntaxError: expected ':'
"Erro de sintaxe: era esperado :". A setinha aponta exatamente para o fim da linha, onde faltam os dois-pontos. Como consertar: class Produto:.
NameError
cafe = Produto()
class Produto:
pass
$ python3 antes.py
Traceback (most recent call last):
File "/home/ana/antes.py", line 1, in <module>
cafe = Produto()
^^^^^^^
NameError: name 'Produto' is not defined
"O nome Produto não está definido". O Python lê o arquivo de cima para baixo. Na linha 1, a classe ainda não existe: ela só é criada na linha 4. É como pedir um bolo antes de alguém ter comprado a forma. Como consertar: escreva a classe antes de usá-la, no começo do arquivo.
Missão: o programa dá AttributeError. Rode, leia a mensagem e conserte: o café custa 18.90.
class Produto:
pass
cafe = Produto()
cafe.nome = "Café"
print(cafe.nome, cafe.preco)
class Produto:
pass
cafe = Produto()
cafe.nome = "Café"
cafe.preco = 18.90
print(cafe.nome, cafe.preco)
Referência rápida
| Escrita | O que faz |
|---|---|
class Produto: + bloco recuado | Cria a classe (o modelo) Produto |
pass | Não faz nada; ocupa o lugar de um bloco vazio |
cafe = Produto() | Cria um objeto (uma instância) da classe e guarda em cafe |
cafe.nome = "Café" | Cria ou troca o atributo nome do objeto cafe |
cafe.nome | Lê o atributo nome do objeto cafe |
type(cafe) | A classe do objeto: <class '__main__.Produto'> |
isinstance(cafe, Produto) | True se cafe for um Produto |
vars(cafe) | Os atributos do objeto, como dicionário |
| Sintoma | Causa provável |
|---|---|
AttributeError: 'Produto' object has no attribute 'preco' | O atributo não foi criado, ou o nome está digitado errado |
print(x) mostra <class '__main__.Produto'>, e um objeto muda o outro | Faltaram os parênteses: Produto no lugar de Produto() |
IndentationError: expected an indented block after class definition | Classe vazia: ponha um pass |
SyntaxError: expected ':' | Faltaram os dois-pontos depois do nome da classe |
NameError: name 'Produto' is not defined | A classe foi usada antes de ser criada (ou o nome está errado: produto ≠ Produto) |
Exercícios
1. Criando a classe
Complete a palavra-chave que cria uma classe:
pass
2. Fazendo um bolo com a forma
Complete para criar um objeto da classe Aluno (não esqueça o que transforma a forma em bolo):
3. Qual é a relação entre Produto e cafe em cafe = Produto()?
4. A Ana rodou o mesmo programa duas vezes e o print(cafe) mostrou 0x7f7351990590 na primeira e 0x7f8bdaf90590 na segunda. O que aconteceu?
5. Qual destes nomes segue o costume do Python para uma classe?
6. a = Aluno(), b = Aluno(), depois a.nota = 10. Quanto vale b.nota?
Missão final: as contas da Ana e da Bia
Missão: o banco do bairro tem a classe ContaBancaria. A conta da Ana já existe. (1) Crie a conta da Bia, guardada em conta_bia, com o titular "Bia" e o saldo 80.00. (2) A Ana depositou 50 reais: aumente o saldo dela para 150. O programa deve mostrar Ana: R$ 150.00 e Bia: R$ 80.00.
class ContaBancaria:
pass
conta_ana = ContaBancaria()
conta_ana.titular = "Ana"
conta_ana.saldo = 100.00
# 1. crie aqui a conta da Bia
# 2. a Ana depositou 50 reais
print(f"{conta_ana.titular}: R$ {conta_ana.saldo:.2f}")
print(f"{conta_bia.titular}: R$ {conta_bia.saldo:.2f}")
class ContaBancaria:
pass
conta_ana = ContaBancaria()
conta_ana.titular = "Ana"
conta_ana.saldo = 100.00
# 1. crie aqui a conta da Bia
conta_bia = ContaBancaria()
conta_bia.titular = "Bia"
conta_bia.saldo = 80.00
# 2. a Ana depositou 50 reais
conta_ana.saldo = conta_ana.saldo + 50
print(f"{conta_ana.titular}: R$ {conta_ana.saldo:.2f}")
print(f"{conta_bia.titular}: R$ {conta_bia.saldo:.2f}")
Dica: conta_ana.saldo += 50 também funciona; o += (aula Operadores de Atribuição) vale para atributos como vale para variáveis. Repare que o depósito na conta da Ana não mexeu no saldo da Bia.
Resumo
- A classe é o modelo (a forma de bolo, a ficha em branco); o objeto, ou instância, é a coisa feita a partir dela (o bolo, a ficha preenchida).
class Produto:cria a classe;Produto(), com parênteses, cria um objeto. Sem os parênteses, você só ganha outro nome para a classe.- Nomes de classe começam com maiúscula, cada palavra com maiúscula:
ContaBancaria. <__main__.Produto object at 0x7f…>é o jeito padrão de mostrar um objeto; o endereço muda a cada execução.- Cada objeto guarda os seus próprios atributos:
cafe.preco = 21.00não mexe empao.preco. Ler um atributo que não existe dáAttributeError. type(cafe)diz a classe;isinstance(cafe, Produto)responde se é um produto.- Em Python, tudo é objeto:
"ana"é uma instância destr,42deint. - Próxima aula: __init__ e self, para que todo objeto já nasça com os seus dados.