Python mixins是反模式吗?


34

我完全意识到,pylint其他静态分析工具并非一无所知,有时必须不听从他们的建议。(这适用于各种类型的消息,而不仅仅是conventions。)


如果我有像

class related_methods():

    def a_method(self):
        self.stack.function(self.my_var)

class more_methods():

    def b_method(self):
        self.otherfunc()

class implement_methods(related_methods, more_methods):

    def __init__(self):
        self.stack  = some()
        self.my_var = other()

    def otherfunc(self):
        self.a_method()

显然,这是人为的。如果您愿意,这是一个更好的示例

我相信使用“ mixins”来称呼这种风格。

像其他工具,pylint利率这个代码的-21.67 / 10,主要是因为它认为more_methodsrelated_methods没有self或属性otherfuncstack,annd my_var因为没有运行的代码,它显然不能看到related_methodsmore_methods在混合中implement_methods

编译器和静态分析工具不能总是解决Halting问题,但是我认为这确实是一种情况,其中查看继承者的内容implement_methods将证明这是完全有效的,并且这很容易做到。

为什么静态分析工具会拒绝这种有效的(我认为)OOP模式?

要么:

  1. 他们甚至不尝试检查继承或

  2. 不鼓励在惯用且易读的Python中使用mixins


#1显然是不正确,因为如果我问pylint告诉我的一类矿井的继承unittest.TestCase使用 self.assertEqual,(仅定义的东西unittest.TestCase),它并没有抱怨。

mixins是unpythonic还是不鼓励使用?


1
这是一个坏问题吗?是题外话吗?它无法回答吗?我很傻吗 人们可以使用DV,但他们不想帮助改进它。

1
有些人可能会厌烦人们问“这是(反)模式”还是“这是(非)Python语言”。

9
@MichaelT很好。然后他们可以停止复习问题。
Katana314 '16

2
@tac人们会出于各种原因而拒绝投票,但是永远不需要说为什么-拒绝按钮上有一个工具提示,上面写着“这个问题没有显示任何研究成果;不清楚或没有用”-含糊不清,如果可接受的答案。实际上,向上8向下1倒是相当不错的,特别是在一个免费下载downdown的问题上。不要让它让你失望。干杯。
亚伦·霍尔

@AaronHall我知道人们可以通过投票来做自己喜欢的事情,的确,我告诉抱怨同样事情的新用户。

Answers:


16

Mixins并不是该工具考虑的用例。这并不意味着它一定是一个不好的用例,而对于python来说却并不常见。

在特定情况下是否适当使用mixin是另一回事。我经常看到的mixin反模式是在仅打算混合一种组合的情况下使用mixins。这只是隐藏神职人员的回旋处。如果你不能想出一个理由,现在换出或者离开了混入之一,它不应该是一个mixin。


是的,我承认这是神的对象。在这种情况下,我认为将CPU作为上帝对象是可以的。

15

我相信Mixins绝对可以是Pythonic。但是,使您的liner安静下来并提高Mixin的可读性的惯用方式是(1)定义抽象方法,这些方法明确定义了需要Mixin的子代实现的方法,以及(2)预定义None子项必须初始化的Mixin数据成员的值字段。

将此模式应用于您的示例:

from abc import ABC, abstractmethod


class related_methods():
    my_var = None
    stack = None

    def a_method(self):
        self.stack.function(self.my_var)


class more_methods(ABC):
    @abstractmethod
    def otherfunc(self):
        pass

    def b_method(self):
        self.otherfunc()


class implement_methods(related_methods, more_methods):
    def __init__(self):
        self.stack  = some()
        self.my_var = other()

    def otherfunc(self):
        self.a_method()

2
为您的答案+1,尽管这abstract other(self): pass件事将短毛绒的混乱换成了我的
猫猫

如果没有@abstractmethod,这会更加令人困惑;-)我首先开始使用Java,所以这对我来说很好。
克里斯·黄·利弗

9

我认为 mixins可能很好,但是我也认为pylint在这种情况下是正确的。免责声明:基于意见的内容如下。

一个好的类(包括mixins)负有明确的责任。理想情况下,mixin应该包含它将要访问的所有状态以及处理该状态的逻辑。例如,一个好的mixin可以将一个last_updated字段添加到ORM模型类中,为设置它提供逻辑,并提供搜索最早/最新记录的方法。

引用未声明的实例成员(变量和方法)确实有些怪异。

正确的方法很大程度上取决于手头的任务。

它可能是一个mixin,其中保留了相关的状态位。

可能是不同的类层次结构,当前您通过mixin分发的方法位于基类中,而较低级别的实现差异属于子类。这看起来最适合您使用堆栈操作的情况。

它可能是添加一个或两个方法的类装饰器。当您必须将一些参数传递给装饰器以影响方法的生成时,这通常很有意义。

陈述您的问题,解释更大的设计问题,然后我们可以争论您是否遇到某种反模式。


6

linter不知道您将类用作mixin。如果您在类名的末尾添加了后缀'mixin'或'Mixin',则Pylint会意识到您使用了mixin,这样短绒棉就不再抱怨了。

linter_without_mixins linter2_with_mixin

Mixins本身并不坏,也仅是一种工具。您使它们很好用或不好用。


2
这读起来更像是一条评论,请参阅“ 如何回答
gna

2
这是一个有价值的答案,因为我不认为我会永远知道该提示,否则

1

mixins可以吗?

Python mixins是反模式吗?

不鼓励使用混合包-它们是多重继承的好用例。

你的孩子为什么抱怨?

pylint的显然是抱怨,因为它不知道在哪里otherfuncstack以及my_var 是哪里来的。

不重要的?

没有直接明显的理由将您将这两种方法分为单独的父类,无论是在问题中的示例中,还是在如上所示的更平凡的链接示例中。

201
202 class OpCore():
203     # nothing runs without these
204
205 class OpLogik(): 
206     # logic methods... 
207 
208 class OpString(): 
209     # string things
210 
211 
212 class Stack(OpCore, OpLogik, OpString): 
213 
214     "the mixin mixer of the above mixins" 

混音和噪声的成本

您正在做的事情是使皮特报告噪音大。这种噪音可能会掩盖您的代码中更重要的问题。这是权衡的重要成本。另一个代价是将相互关联的代码分为不同的命名空间,这可能会使程序员更难发现其含义。

结论

继承允许代码重用。如果您使用mixins进行代码重用,那就太好了,它们为您创造的价值可能超过其他可能的成本。如果您没有获得代码重用/重复执行代码行的代码,则可能没有为Mixin带来太多价值,到那时,我认为噪声的代价要大于收益。


在链接的非平凡示例中将它们分开是有充分的理由的-当我有一部分完整的类实现数学,另一个完整的类实现字符串,等等,并且将它们混合在一起时,对于我来说组织代码更容易去拿汤。
2016年

“另一个代价是将代码分成不同的命名空间,这可能会使程序员更难发现……的含义。” -不,根本不是这样。类名称空间使您更容易知道一组方法的作用,并且当有人想使用堆栈时,他们应该调用/实现Forth Soup,而不是单独的成分
Cat

@cat可能是因为它们是人为设计的,而不是在真正的大型项目中使用的,这两个示例都无法真正支持您使用mixins的观点。两者都只显示了一次使用mixin的情况,在这种情况下,将实现放在一处是更好的样式和组织。现在,如果您可以显示一种情况,您希望跨类使用通用功能,但又不想使用通用基类,那么您将在这里使用mixin。您的棉绒问题旁边(UltraBird回答得很好)。但这通常回答您有关mixin适用性的问题。
dlamblin '18年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.