What does Pylint's "Too few public methods" message mean?
The error basically says that classes aren't meant to just store data, as you're basically treating the class as a dictionary. Classes should have at least a few methods to operate on the data that they hold.
If your class looks like this:
class MyClass(object):
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
Consider using a dictionary or a namedtuple
instead. Although if a class seems like the best choice, use it. Pylint doesn't always know what's best.
Do note that namedtuple
is immutable and the values assigned on instantiation cannot be modified later.
If you are extending a class, then my suggestion is to systematically disable this warning and move on, e.g., in the case of Celery tasks:
class MyTask(celery.Task): # pylint: disable=too-few-public-methods
"""base for My Celery tasks with common behaviors; extends celery.Task
...
Even if you are only extending a single function, you definitely need a class to make this technique function, and extending is definitely better than hacking on the third-party classes!
This is another case of Pylint's blind rules.
"Classes are not meant to store data" - this is a false statement. Dictionaries are not good for everything. A data member of a class is something meaningful, a dictionary item is something optional. Proof: you can do dictionary.get('key', DEFAULT_VALUE)
to prevent a KeyError
, but there is no simple __getattr__
with default.
Recommended ways for using structs
I need to update my answer. Right now - if you need a struct
, you have two great options:
a) Just use attrs
These is a library for that:
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()
What you get extra: not writing constructors, default values, validation, __repr__
, read-only objects (to replace namedtuples
, even in Python 2) and more.
b) Use dataclasses
(Py 3.7+)
Following hwjp's comment, I also recommend dataclasses
:
https://docs.python.org/3/library/dataclasses.html
This is almost as good as attrs
, and is a standard library mechanism ("batteries included"), with no extra dependencies, except Python 3.7+.
The rest of the previous answer
NamedTuple
is not great - especially before Python 3's typing.NamedTuple
:
https://docs.python.org/3/library/typing.html#typing.NamedTuple
- you definitely should check out the "class derived from
NamedTuple
" pattern. Python 2 -namedtuples
created from string descriptions - is ugly, bad and "programming inside string literals" stupid.
I agree with the two current answers ("consider using something else, but Pylint isn't always right" - the accepted one, and "use Pylint suppressing comment"), but I have my own suggestion.
Let me point this out one more time: Some classes are meant just to store data.
Now the option to also consider - 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
Above you have read-only properties, which is OK for Value Object (e.g., like those in Domain Driven Design), but you can also provide setters - this way your class will be able to take responsibility for the fields which you have - for example to do some validation etc. (if you have setters, you can assign using them in the constructor, i.e., self.foo = foo
instead of direct self._foo = foo
, but careful, the setters may assume other fields to be initialized already, and then you need custom validation in the constructor).