Это еще один случай pylint
слепых правил России.
«Классы не предназначены для хранения данных» - это ложное утверждение. Словари подходят не для всего. Член данных класса - это что-то значимое, элемент словаря - это нечто необязательное. Доказательство: вы можете сделать, dictionary.get('key', DEFAULT_VALUE)
чтобы предотвратить a KeyError
, но по __getattr__
умолчанию нет простого .
EDIT - рекомендуемые способы использования структур
Мне нужно обновить свой ответ. Прямо сейчас - если вам нужен struct
, у вас есть два отличных варианта:
а) Просто используйте attrs
Это библиотека для этого:
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()
Что вы получаете дополнительно: отказ от написания конструкторов, значений по умолчанию, проверки, __repr__
объекты только для чтения (для замены namedtuples
, даже в Python 2) и многое другое.
б) Используйте dataclasses
(Py 3.7+)
Следуя комментарию hwjp, я также рекомендую dataclasses
:
https://docs.python.org/3/library/dataclasses.html
Это почти так же хорошо, как attrs
и стандартный библиотечный механизм («батарейки включены»), без дополнительных зависимостей, кроме Python 3.7+.
Остальная часть предыдущего ответа
NamedTuple
не очень хорошо - особенно до Python 3 typing.NamedTuple
:
https://docs.python.org/3/library/typing.html#typing.NamedTuple
- вам определенно следует проверить NamedTuple
шаблон «класс, производный от ». Python 2, namedtuples
созданный из строковых описаний, уродлив, плох, а "программирование внутри строковых литералов" глупо.
Я согласен с двумя текущими ответами («подумайте об использовании чего-то еще, но pylint не всегда правильный» - принятый и «используйте комментарий, подавляющий pylint»), но у меня есть собственное предложение.
Позвольте мне указать на это еще раз: некоторые классы предназначены только для хранения данных.
Теперь возможность также рассмотреть - используйте 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
Выше у вас есть свойства только для чтения, которые подходят для объекта значения (например, как в доменном дизайне), но вы также можете предоставить сеттеры - таким образом ваш класс сможет взять на себя ответственность за поля, которые у вас есть - например для выполнения некоторой проверки и т. д. (если у вас есть сеттеры, вы можете назначить их использование в конструкторе, то есть self.foo = foo
вместо прямого self._foo = foo
, но осторожного, сеттеры могут предположить, что другие поля уже инициализированы, и тогда вам понадобится настраиваемая проверка в конструкторе) .