Este é outro caso de pylint
regras cegas de.
"As classes não têm como objetivo armazenar dados" - esta é uma afirmação falsa. Os dicionários não são bons para tudo. Um membro de dados de uma classe é algo significativo, um item de dicionário é algo opcional. Prova: você pode fazer dictionary.get('key', DEFAULT_VALUE)
para prevenir um KeyError
, mas não é simples __getattr__
com o padrão.
EDITAR - maneiras recomendadas de usar estruturas
Eu preciso atualizar minha resposta. Agora - se você precisar de umstruct
, você tem duas ótimas opções:
a) Basta usar attrs
Esta é uma biblioteca para isso:
https://www.attrs.org/en/stable/
import attr
@attr.s
class MyClass(object): # or just MyClass: for Python 3
foo = attr.ib()
bar = attr.ib()
O que você ganha extra: não escrever construtores, valores padrão, validação, __repr__
objetos somente leitura (para substituir namedtuples
, mesmo no Python 2) e muito mais.
b) Use dataclasses
(Py 3.7+)
Após o comentário de hwjp, também recomendo dataclasses
:
https://docs.python.org/3/library/dataclasses.html
Isso é quase tão bom quanto attrs
, e é um mecanismo de biblioteca padrão ("baterias incluídas"), sem dependências extras, exceto Python 3.7+.
Resto da resposta anterior
NamedTuple
não é ótimo - especialmente antes do python 3 typing.NamedTuple
:
https://docs.python.org/3/library/typing.html#typing.NamedTuple
- você definitivamente deve verificar o NamedTuple
padrão "classe derivada de ". Python 2 - namedtuples
criado a partir de descrições de string - é feio, ruim e "programar dentro de literais de string" é estúpido.
Concordo com as duas respostas atuais ("considere usar outra coisa, mas o pylint nem sempre está certo" - a aceita e "use o comentário de supressão do pylint"), mas tenho minha própria sugestão.
Deixe-me apontar isso mais uma vez: algumas classes destinam-se apenas a armazenar dados.
Agora, a opção de considerar também - use property
-ies.
class MyClass(object):
def __init__(self, foo, bar):
self._foo = foo
self._bar = bar
@property
def foo(self):
return self._foo
@property
def bar(self):
return self._bar
Acima você tem propriedades somente leitura, o que é OK para Value Object (por exemplo, como aquelas em Domain Driven Design), mas você também pode fornecer setters - desta forma, sua classe será capaz de assumir a responsabilidade pelos campos que você possui - por exemplo para fazer alguma validação etc. (se você tiver setters, você pode atribuir usando-os no construtor, ou seja, em self.foo = foo
vez de direto self._foo = foo
, mas cuidado, os setters podem assumir que outros campos já foram inicializados, e então você precisa de validação personalizada no construtor) .