Python @classmethod e @staticmethod
Até aqui, todo método que você escreveu começava com self: ele trabalha com um objeto (este café, aquele aluno). Mas algumas tarefas pertencem à classe sem pertencer a nenhum objeto em especial. "Quantos produtos a lojinha já cadastrou?" é uma pergunta sobre a classe Produto, não sobre o café. "Transforme o número 1234.5 no texto R$ 1.234,50" nem precisa de produto nenhum. Para esses casos, o Python tem dois tipos de método: o método de classe, marcado com @classmethod, e o método estático, marcado com @staticmethod.
- A diferença entre os três tipos de método: o normal (
self), o de classe (cls) e o estático (nenhum dos dois). - O que é a "arroba" (
@) em cima dodef. - A usar um método de classe para contar os objetos criados.
- O uso mais comum do
@classmethod: um segundo jeito de criar objetos, comoProduto.de_texto("Café;18.90"). - Por que escrever
cls(...)e nãoProduto(...)dentro dele (e o defeito silencioso que aparece com herança). - Quando um
@staticmethodfaz sentido e quando uma função comum é melhor. - Os erros reais:
missing 1 required positional argument: 'self',takes 1 positional argument but 2 were givene companhia.
A ideia: a fábrica, o bolo e a balança
Pense numa fábrica de bolos. A receita é a classe; cada bolo que sai do forno é um objeto. Agora repare em três perguntas diferentes:
- "Qual é o sabor deste bolo?" Só dá para responder olhando um bolo. É um método normal: recebe o bolo (o
self). - "Quantos bolos a fábrica já fez hoje?" "Faça um bolo a partir deste pedido escrito num papel." São tarefas da fábrica, não de um bolo. É um método de classe: recebe a classe (o
cls). - "Quanto são 250 gramas em xícaras?" A balança da cozinha responde sem olhar bolo nenhum e sem saber nada da fábrica. Ela só fica guardada ali porque é coisa de cozinha. É um método estático: não recebe nem o bolo nem a fábrica.
| Tipo de método | Marca | Primeiro parâmetro | Trabalha com… |
|---|---|---|---|
| Normal (de instância) | nenhuma | self (o objeto) | os dados de um objeto |
| De classe | @classmethod | cls (a classe) | a classe inteira: contadores, outros jeitos de criar objetos |
| Estático | @staticmethod | nenhum especial | só com os argumentos que recebe |
1. Lembrando: o método normal recebe self
A lojinha da Ana tem uma classe Produto, com o nome e o preço de cada produto, como nas aulas __init__ e self e Atributos e Métodos:
class Produto:
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
def descricao(self):
return f"{self.nome}: R$ {self.preco:.2f}"
cafe = Produto("Café", 18.9)
print(cafe.descricao())
$ python3 normal.py Café: R$ 18.90
Quando você escreve cafe.descricao(), o Python entrega o próprio cafe no parâmetro self. É por isso que descricao consegue ler self.nome: ela sabe de qual produto está falando. Guarde isso, porque os outros dois tipos de método mudam justamente o que chega no primeiro parâmetro.
2. O primeiro @classmethod: o contador da lojinha
A Ana quer saber quantos produtos já foram cadastrados. Esse número não é de um produto; é da classe. Ele fica num atributo da classe (escrito dentro da classe, fora de qualquer método), e quem o mostra é um método de classe:
class Produto:
criados = 0 # atributo da classe: um só, para todos os produtos
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
Produto.criados += 1
@classmethod
def total(cls):
return f"A lojinha já cadastrou {cls.criados} produtos."
print(Produto.total())
cafe = Produto("Café", 18.9)
leite = Produto("Leite", 5.49)
print(Produto.total())
print(cafe.total())
- criados = 0
- Um atributo da classe. Existe uma cópia só, que todos os produtos compartilham, ao contrário de
self.nome, que cada produto tem o seu. - Produto.criados += 1
- Toda vez que um produto nasce, o
__init__soma 1 ao contador da classe. - @classmethod
- Um decorador (do inglês decorator, "enfeite"): uma linha que começa com
@, fica logo acima dodefe muda o jeito como aquele método funciona. Este diz: "este é um método de classe". Decoradores têm aula própria, Decoradores; aqui basta saber usar estes dois. - def total(cls):
- O primeiro parâmetro agora se chama
cls(abreviação de class, "classe"). Nele o Python entrega a classe, e não um objeto. O nomeclsé só costume, comoself; mas é o costume que todo mundo segue. - cls.criados
- Lê o atributo da classe através do
cls. - Produto.total()
- Chama o método direto pela classe, sem precisar de nenhum objeto.
$ python3 contador.py A lojinha já cadastrou 0 produtos. A lojinha já cadastrou 2 produtos. A lojinha já cadastrou 2 produtos.
Três coisas para reparar:
- A primeira linha saiu antes de existir qualquer produto. Um método normal não conseguiria isso: sem objeto, não há
self. - Depois do café e do leite, o contador foi para 2.
cafe.total()também funciona, e dá o mesmo resultado. Mesmo chamado por um objeto, oclsrecebe a classe do objeto, nunca o objeto. O costume, porém, é chamar pela classe (Produto.total()), que deixa claro que a pergunta é sobre a lojinha toda.
O que chega no cls, afinal?
Dá para conferir com um print:
class Produto:
@classmethod
def mostrar(cls):
print("cls é:", cls)
print("cls é Produto?", cls is Produto)
Produto.mostrar()
$ python3 cls.py cls é: <class '__main__.Produto'> cls é Produto? True
<class '__main__.Produto'> é como o Python mostra uma classe: "a classe Produto, criada no programa principal" (__main__ é o nome que o Python dá ao arquivo que você mandou rodar). E cls is Produto deu True: dentro do método, cls é a própria classe Produto.
3. O uso mais comum: outro jeito de criar objetos
A Ana recebe a lista de preços do fornecedor num arquivo de texto, uma linha por produto, assim: Arroz 5 kg;27.50. Para criar o produto, ela teria de separar o texto, converter o preço e só então chamar Produto(...), toda vez. Fica muito melhor ensinar a própria classe a fazer isso:
class Produto:
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
@classmethod
def de_texto(cls, linha):
nome, preco = linha.split(";")
return cls(nome, float(preco))
def descricao(self):
return f"{self.nome}: R$ {self.preco:.2f}"
cafe = Produto("Café", 18.9)
arroz = Produto.de_texto("Arroz 5 kg;27.50")
print(cafe.descricao())
print(arroz.descricao())
print(type(arroz))
- def de_texto(cls, linha):
- Recebe a classe (
cls) e a linha de texto. - nome, preco = linha.split(";")
- Corta o texto no ponto e vírgula e guarda as duas partes (aulas Métodos de Texto e Desempacotamento).
- cls(nome, float(preco))
- Como
clsé a classe,cls(...)é o mesmo queProduto(...): cria um produto novo, passando pelo__init__de sempre. - return
- Devolve o produto pronto.
$ python3 de_texto.py Café: R$ 18.90 Arroz 5 kg: R$ 27.50 <class '__main__.Produto'>
Agora a classe tem duas portas de entrada: Produto("Café", 18.9), quando você já tem o nome e o preço separados, e Produto.de_texto("Arroz 5 kg;27.50"), quando tem a linha do fornecedor. Os dois caminhos terminam no mesmo __init__ e dão o mesmo tipo de objeto. Um método assim se chama construtor alternativo.
O próprio Python faz assim
Você já pode ter usado construtores alternativos sem saber. Eles costumam ter nomes que começam com from ("a partir de"):
from datetime import date
estoque = dict.fromkeys(["café", "leite", "pão"], 0)
print(estoque)
aniversario = date.fromisoformat("2026-03-12")
print(aniversario)
print(type(aniversario))
print(int.from_bytes(b"\x01\x00", "big"))
$ python3 do_python.py
{'café': 0, 'leite': 0, 'pão': 0}
2026-03-12
<class 'datetime.date'>
256
dict.fromkeys cria um dicionário "a partir de uma lista de chaves"; date.fromisoformat cria uma data "a partir de um texto no formato ano-mês-dia" (aula Datas e Horas); int.from_bytes cria um número "a partir de bytes". Todos são métodos de classe: você chama pela classe (dict, date, int) e recebe um objeto novo. Nos seus programas, em português, nomes como de_texto, de_dicionario e de_linha_csv seguem a mesma ideia.
Missão: o programa chama Produto.de_texto(...), mas o método ainda não existe (rode para ver o erro). Crie o método de classe de_texto, que recebe "Feijão;8.79" e devolve um Produto.
class Produto:
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
# crie aqui o método de classe de_texto
def descricao(self):
return f"{self.nome}: R$ {self.preco:.2f}"
feijao = Produto.de_texto("Feijão;8.79")
print(feijao.descricao())
class Produto:
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
@classmethod
def de_texto(cls, linha):
nome, preco = linha.split(";")
return cls(nome, float(preco))
def descricao(self):
return f"{self.nome}: R$ {self.preco:.2f}"
feijao = Produto.de_texto("Feijão;8.79")
print(feijao.descricao())
4. Por que cls(...), e não Produto(...)?
Dentro de de_texto, escrever Produto(nome, float(preco)) parece dar no mesmo. E dá, até o dia em que aparece uma classe filha (aula Herança). A Ana criou a classe Importado, que herda tudo de Produto e só muda a descrição. Veja a diferença entre usar cls e escrever o nome da classe à mão:
class Produto:
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
def descricao(self):
return f"{self.nome}: R$ {self.preco:.2f}"
@classmethod
def de_texto(cls, linha):
nome, preco = linha.split(";")
return cls(nome, float(preco))
@classmethod
def de_texto_fixo(cls, linha):
nome, preco = linha.split(";")
return Produto(nome, float(preco)) # nome da classe escrito à mão
class Importado(Produto):
def descricao(self):
return f"{self.nome} (importado): R$ {self.preco:.2f}"
azeite = Importado.de_texto("Azeite;42.00")
print(type(azeite).__name__)
print(azeite.descricao())
vinho = Importado.de_texto_fixo("Vinho;59.90")
print(type(vinho).__name__)
print(vinho.descricao())
$ python3 heranca.py Importado Azeite (importado): R$ 42.00 Produto Vinho: R$ 59.90
Os dois métodos foram chamados pela classe Importado. Mas:
de_textousacls. Chamado porImportado, oclséImportado, e o azeite nasceu importado, com a descrição certa.de_texto_fixoescreveProdutoà mão. Não importa por qual classe foi chamado: sempre cria umProdutocomum. O vinho perdeu o "(importado)" e nenhum erro apareceu. É o pior tipo de defeito, o que passa calado.
(type(azeite).__name__ mostra só o nome da classe do objeto, sem o <class '__main__....'> em volta.)
Dentro de um @classmethod, fale sempre da classe pelo cls: cls(...) para criar, cls.criados para ler um atributo da classe. Assim o método continua certo nas classes filhas.
5. O @staticmethod: uma ferramenta guardada na classe
Algumas funções têm tudo a ver com produtos, mas não precisam de produto nenhum para trabalhar: "este preço é válido?", "como fica este número em reais?". Elas recebem um valor e devolvem uma resposta. Para guardá-las dentro da classe, use @staticmethod ("método estático"):
class Produto:
def __init__(self, nome, preco):
if not Produto.preco_valido(preco):
raise ValueError(f"preço inválido: {preco}")
self.nome = nome
self.preco = preco
@staticmethod
def preco_valido(valor):
return valor > 0
@staticmethod
def em_reais(valor):
texto = f"{valor:,.2f}"
return "R$ " + texto.replace(",", "X").replace(".", ",").replace("X", ".")
print(Produto.preco_valido(18.9))
print(Produto.preco_valido(-3))
print(Produto.em_reais(1234.5))
cafe = Produto("Café", 18.9)
print(cafe.em_reais(cafe.preco))
- @staticmethod
- Diz: "este método não recebe nada automaticamente". Nem o objeto, nem a classe.
- def preco_valido(valor):
- Sem
selfe semcls. Ovaloré um parâmetro comum, que você passa na chamada. - return valor > 0
- Devolve
TrueouFalse. - f"{valor:,.2f}"
- Formata com vírgula separando os milhares e duas casas decimais:
1,234.50, o jeito americano (aula Formatação). - .replace(",", "X")…
- Troca a vírgula pelo ponto e o ponto pela vírgula, passando por um
Xprovisório para uma troca não desfazer a outra:1.234,50. - Produto.preco_valido(preco)
- Dentro do
__init__, o método estático é chamado pela classe, como qualquer outro.
$ python3 estatico.py True False R$ 1.234,50 R$ 18,90
O método estático funciona chamado pela classe (Produto.em_reais(1234.5)) ou por um objeto (cafe.em_reais(cafe.preco)). Nos dois casos, ele recebe só o que está entre os parênteses. Repare que, mesmo chamado pelo café, foi preciso passar cafe.preco: o método não enxerga o café.
Missão: a Ana guardou em_reais dentro da classe, mas esqueceu uma linha, e o programa dá TypeError. Rode, leia o erro e conserte.
class Produto:
def em_reais(valor):
return f"R$ {valor:.2f}"
cafe = Produto()
print(cafe.em_reais(18.9))
print(Produto.em_reais(5.49))
class Produto:
@staticmethod
def em_reais(valor):
return f"R$ {valor:.2f}"
cafe = Produto()
print(cafe.em_reais(18.9))
print(Produto.em_reais(5.49))
6. Os três lado a lado
class Produto:
def normal(self):
return "normal"
@classmethod
def da_classe(cls):
return "da classe"
@staticmethod
def estatico():
return "estático"
p = Produto()
print(p.normal(), p.da_classe(), p.estatico())
print(Produto.da_classe(), Produto.estatico())
$ python3 tres.py normal da classe estático da classe estático
| Normal | @classmethod | @staticmethod | |
|---|---|---|---|
| O Python entrega sozinho… | o objeto, em self | a classe, em cls | nada |
Lê os dados do objeto (self.nome)? | Sim | Não | Não |
| Lê os atributos da classe? | Sim | Sim, por cls | Só escrevendo o nome da classe |
Chamar pelo objeto (p.metodo()) | Sim | Sim | Sim |
Chamar pela classe (Produto.metodo()) | Não (falta o self) | Sim | Sim |
| Uso típico | quase tudo | construtores alternativos, contadores | funções utilitárias ligadas ao assunto da classe |
Formas diferentes de fazer a mesma coisa
Método estático ou função comum?
Um @staticmethod é, na prática, uma função comum que mora dentro da classe. Muitas vezes, uma função solta no arquivo resolve igual:
def em_reais(valor):
return f"R$ {valor:.2f}"
class Produto:
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
def descricao(self):
return f"{self.nome}: {em_reais(self.preco)}"
print(em_reais(7.5))
print(Produto("Pão de queijo", 7.5).descricao())
$ python3 funcao_solta.py R$ 7.50 Pão de queijo: R$ 7.50
Muitos programadores Python preferem essa forma: a função fica disponível para o programa todo (inclusive para quem não tem nada a ver com produtos). O @staticmethod vale a pena quando a função só faz sentido junto da classe, e você quer que quem lê Produto.preco_valido(...) entenda na hora que é uma regra dos produtos.
Construtor alternativo ou um __init__ que aceita tudo?
Outra forma seria um __init__ que testa se recebeu um texto ou dois valores, cheio de if. Funciona, mas fica confuso: Produto("Arroz;27.50") não diz o que está acontecendo. Produto.de_texto("Arroz;27.50") diz. Prefira um __init__ simples e um método de classe para cada formato diferente.
| Você precisa… | Use |
|---|---|
Trabalhar com os dados de um objeto (self.preco) | Método normal |
| Criar objetos a partir de outro formato (texto, dicionário, linha de CSV) | @classmethod que termina em return cls(...) |
| Ler ou mudar algo da classe inteira (um contador) | @classmethod |
| Uma regra ou conta que só usa os argumentos e só faz sentido com a classe | @staticmethod |
| Uma conta útil para o programa todo | Função comum, fora da classe |
Quando dá errado
class Produto:
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
def descricao(self):
return f"{self.nome}: R$ {self.preco:.2f}"
print(Produto.descricao())
$ python3 erro_self.py
Traceback (most recent call last):
File "/home/ana/erro_self.py", line 10, in <module>
print(Produto.descricao())
~~~~~~~~~~~~~~~~~^^
TypeError: Produto.descricao() missing 1 required positional argument: 'self'
Linha por linha:
Traceback (most recent call last): "rastro (a chamada mais recente por último)". O Python vai mostrar o caminho até o erro.File "/home/ana/erro_self.py", line 10, in <module>: o erro aconteceu na linha 10, no corpo principal do arquivo (<module>).- Os
~~~^^embaixo da linha apontam a chamada que falhou:Produto.descricao(). TypeError: Produto.descricao() missing 1 required positional argument: 'self': "erro de tipo: está faltando 1 argumento obrigatório, oself".
Chamado pela classe, o método normal não sabe de qual produto deve falar, e ninguém preencheu o self. Como consertar: crie um objeto e chame por ele (cafe.descricao()). Se o método realmente não precisa de objeto, ele deveria ser @classmethod ou @staticmethod.
@staticmethod
class Produto:
def em_reais(valor):
return f"R$ {valor:.2f}"
cafe = Produto()
print(cafe.em_reais(18.9))
$ python3 erro_static.py
Traceback (most recent call last):
File "/home/ana/erro_static.py", line 7, in <module>
print(cafe.em_reais(18.9))
~~~~~~~~~~~~~^^^^^^
TypeError: Produto.em_reais() takes 1 positional argument but 2 were given
"em_reais() recebe 1 argumento, mas foram passados 2." Você só escreveu um (18.9)! O segundo é o objeto: sem decorador, em_reais é um método normal, e o Python entregou o cafe no primeiro parâmetro, o valor. Não sobrou lugar para o 18.9. Como consertar: ponha @staticmethod na linha de cima do def. (Foi a missão do item 5.)
@classmethod sem o cls
class Produto:
criados = 0
@classmethod
def total():
return Produto.criados
print(Produto.total())
$ python3 erro_cls.py
Traceback (most recent call last):
File "/home/ana/erro_cls.py", line 9, in <module>
print(Produto.total())
~~~~~~~~~~~~~^^
TypeError: Produto.total() takes 0 positional arguments but 1 was given
O mesmo problema, ao contrário: o @classmethod sempre entrega a classe no primeiro parâmetro, mas total() não tem parâmetro nenhum para recebê-la. "Recebe 0, foi passado 1." Como consertar: def total(cls):.
@classmethod
class Produto:
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
@classmethod
def descricao(cls):
return f"{cls.nome}: R$ {cls.preco:.2f}"
cafe = Produto("Café", 18.9)
print(cafe.descricao())
$ python3 erro_cls_nome.py
Traceback (most recent call last):
File "/home/ana/erro_cls_nome.py", line 12, in <module>
print(cafe.descricao())
~~~~~~~~~~~~~~^^
File "/home/ana/erro_cls_nome.py", line 8, in descricao
return f"{cls.nome}: R$ {cls.preco:.2f}"
^^^^^^^^
AttributeError: type object 'Produto' has no attribute 'nome'
Agora o rastro tem dois andares: a linha 12 chamou descricao, e o erro estourou lá dentro, na linha 8, em cls.nome. "O objeto-tipo Produto não tem o atributo nome." Mesmo chamado pelo café, o cls é a classe, e o nome mora em cada objeto (self.nome), não na classe. Como consertar: um método que usa os dados de um objeto é um método normal: tire o @classmethod e troque cls por self.
self dentro de um @staticmethod
class Produto:
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
@staticmethod
def descricao():
return f"{self.nome}: R$ {self.preco:.2f}"
cafe = Produto("Café", 18.9)
print(cafe.descricao())
$ python3 erro_static_self.py
Traceback (most recent call last):
File "/home/ana/erro_static_self.py", line 12, in <module>
print(cafe.descricao())
~~~~~~~~~~~~~~^^
File "/home/ana/erro_static_self.py", line 8, in descricao
return f"{self.nome}: R$ {self.preco:.2f}"
^^^^
NameError: name 'self' is not defined
"O nome self não está definido." O self não é uma palavra mágica: é só um parâmetro, e o método estático não tem esse parâmetro. Como consertar: se precisa do objeto, é um método normal (def descricao(self):, sem o decorador).
Referência rápida
| Escrita | O que faz |
|---|---|
def metodo(self): | Método normal: recebe o objeto |
@classmethoddef metodo(cls): | Método de classe: recebe a classe |
@staticmethoddef metodo(x): | Método estático: recebe só os argumentos |
return cls(a, b) | Dentro de um @classmethod: cria um objeto da classe que chamou (funciona com classes filhas) |
Classe.metodo() | Chama um método de classe ou estático sem criar objeto |
dict.fromkeys(chaves, 0), date.fromisoformat(texto) | Construtores alternativos do próprio Python |
| Sintoma | Causa provável |
|---|---|
missing 1 required positional argument: 'self' | Método normal chamado pela classe, sem objeto |
takes 1 positional argument but 2 were given | Faltou o @staticmethod (ou faltou o self num método normal) |
takes 0 positional arguments but 1 was given | Método de classe sem o parâmetro cls |
type object 'Produto' has no attribute 'nome' | Usou cls.nome: o nome é de cada objeto, não da classe |
name 'self' is not defined | Usou self num método estático |
| A classe filha cria objetos da classe mãe, sem erro | O construtor alternativo escreveu o nome da classe em vez de cls |
Exercícios
1. A marca
Complete o decorador que transforma total num método de classe:
def total(cls):
2. O primeiro parâmetro
Complete o primeiro parâmetro do construtor alternativo e a criação do objeto:
def de_texto(, linha):
nome, preco = linha.split(";")
return (nome, float(preco))
3. Num método marcado com @classmethod, o que o Python entrega no primeiro parâmetro quando você escreve cafe.total()?
4. A função converte_kg_em_gramas(kg) só faz uma conta com o número que recebe, e só é usada pelos produtos. Qual é a escolha mais adequada?
5. cafe.em_reais(18.9) deu takes 1 positional argument but 2 were given. O que aconteceu?
6. Por que, dentro de um construtor alternativo, é melhor escrever return cls(...) do que return Produto(...)?
Missão final: o boletim da turma
Missão: a professora da turma da Ana recebe as notas em linhas como "Bia;8.5". Complete a classe Aluno com: (1) um método estático situacao(nota), que devolve "aprovado" se a nota for 7 ou mais e "recuperação" se for menor; (2) um método de classe de_texto(cls, linha), que cria o aluno a partir da linha.
class Aluno:
matriculados = 0
def __init__(self, nome, nota):
self.nome = nome
self.nota = nota
Aluno.matriculados += 1
# 1) crie aqui o método estático situacao(nota)
# 2) crie aqui o método de classe de_texto(cls, linha)
def boletim(self):
return f"{self.nome}: {self.nota} ({Aluno.situacao(self.nota)})"
for linha in ["Bia;8.5", "Caio;6.0", "Duda;9.25"]:
aluno = Aluno.de_texto(linha)
print(aluno.boletim())
print(Aluno.matriculados, "alunos")
class Aluno:
matriculados = 0
def __init__(self, nome, nota):
self.nome = nome
self.nota = nota
Aluno.matriculados += 1
@staticmethod
def situacao(nota):
if nota >= 7:
return "aprovado"
return "recuperação"
@classmethod
def de_texto(cls, linha):
nome, nota = linha.split(";")
return cls(nome, float(nota))
def boletim(self):
return f"{self.nome}: {self.nota} ({Aluno.situacao(self.nota)})"
for linha in ["Bia;8.5", "Caio;6.0", "Duda;9.25"]:
aluno = Aluno.de_texto(linha)
print(aluno.boletim())
print(Aluno.matriculados, "alunos")
Com a solução, o lab mostrou:
$ python3 main.py Bia: 8.5 (aprovado) Caio: 6.0 (recuperação) Duda: 9.25 (aprovado) 3 alunos
Resumo
- O método normal recebe o objeto em
selfe trabalha com os dados dele. - O
@classmethodrecebe a classe emcls, seja chamado pela classe ou por um objeto. Serve para contadores e, principalmente, para construtores alternativos (Produto.de_texto(...), comodict.fromkeysedate.fromisoformat). - Dentro do
@classmethod, crie comcls(...), não com o nome da classe: assim as classes filhas recebem objetos do tipo certo. - O
@staticmethodnão recebe nada automaticamente: é uma função comum guardada na classe. Se ela serve para o programa todo, uma função fora da classe pode ser melhor. - Os erros contam o que faltou ou sobrou no primeiro parâmetro:
missing … 'self',takes 1 … but 2 were given,takes 0 … but 1 was given.