pylint的“公开方法太少”消息是什么意思

问题:pylint的“公开方法太少”消息是什么意思

我在某些代码上运行pylint,并收到错误“公共方法太少(0/2)”。此消息是什么意思?该pylint的文档也没有什么帮助:

当类的公共方法太少时使用,因此请确保它确实值得。

I’m running pylint on some code, and receiving the error “Too few public methods (0/2)”. What does this message mean? The pylint docs are not helpful:

Used when class has too few public methods, so be sure it’s really worth it.


回答 0

该错误基本上表明类并不意味着存储数据,因为您基本上将类视为字典。类至少应具有几种方法来处理它们所保存的数据。

如果您的Class看起来像这样:

class MyClass(object):
    def __init__(self, foo, bar):
        self.foo = foo
        self.bar = bar

考虑使用字典或namedtuple替代字典。尽管如果一堂课似乎是最好的选择,请使用它。pylint并不总是知道什么是最好的。

请注意,这namedtuple是不可变的,实例化时分配的值以后不能修改。

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.


回答 1

如果您要扩展类,那么我的建议是系统地禁用此警告并继续进行,例如,在Celery任务中:

class MyTask(celery.Task):  # pylint: disable=too-few-public-methods                                                                                   
    """base for My Celery tasks with common behaviors; extends celery.Task

    ...             

即使仅扩展单个函数,您也绝对需要一个类来使该技术起作用,并且扩展绝对比黑客第三方类更好!

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!


回答 2

这是pylint的盲目规则的另一种情况。

“类并不意味着存储数据”-这是一个错误的陈述。字典并不能满足所有需求。类的数据成员是有意义的,字典项是可选的。证明:您可以dictionary.get('key', DEFAULT_VALUE)防止KeyError,但__getattr__默认情况下不简单。

编辑-使用结构的推荐方法

我需要更新我的答案。现在-如果需要a struct,则有两个不错的选择:

a)只需使用 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中也要替换),等等。

b)使用dataclasses(Py 3.7+)

根据hwjp的评论,我还建议 dataclasses

https://docs.python.org/3/library/dataclasses.html

这几乎和 attrs,并且是标准的库机制(“包含电池”),没有额外的依赖关系,但Python 3.7+除外。

上一个答案的其余部分

NamedTuple并不是很好-特别是在python 3之前typing.NamedTuplehttps : //docs.python.org/3/library/typing.html#typing.NamedTuple- 您一定要检查“从NamedTuple模式”。namedtuples从字符串描述创建的Python 2 丑陋,糟糕,并且“在字符串文字中编程”是愚蠢的。

我同意两个当前的答案(“考虑使用其他东西,但是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

在上面,您具有只读属性,对于Value Object来说,这是可以的(例如,像域驱动设计中的属性),但是您也可以提供setter-这样,您的类将能够对自己拥有的字段负责进行一些验证等。(如果有设置器,则可以在构造函数中使用它们进行赋值,即self.foo = foo代替Direct self._foo = foo,但要小心,设置器可能会假定其他字段已经初始化,然后需要在构造函数中进行自定义验证) 。

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.

EDIT – 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+.

Rest of 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).


回答 3

当老板期望单一责任原则时,这很困难,但皮林特拒绝了。因此,请向您的Class添加第二种方法,以使您的Class违反单一责任原则。在旁观者的眼中,您打算采取多大责任的原则。

我的解决办法

我在类中添加了一个额外的方法,因此它现在可以完成两件事。

def __str__(self):
    return self.__class__.__name__

我只是想知道我是否现在需要将我的Class分成2个单独的文件,也许还有模块。

问题得到了解决,但我的同事们却没有花一整天的时间讨论规范,而不是像生死攸关的问题那样坚持下去。

It’s hard when your boss expects single responsibility principle, but pylint says no. So add a second method to your class so your class violates single responsibility principle. How far you are meant to take single responsibility principle is in the eye the beholder.

My fix,

I added an extra method to my class, so it now does 2 things.

def __str__(self):
    return self.__class__.__name__

I’m just wondering if I need to split my class into 2 separate files now, and maybe modules aswell.

problem solved, but not with my colleagues who spend all day arguing the spec, rather than getting on with it, like it’s life and death.