mixin 应该使用父属性吗?

J1b*_*1bz 7 python design-patterns mixins

我正在开发一个 python 项目,我需要使用大约 20 个不同的类来实现一系列功能,例如:“下载”、“解析”、“更新”等。

使用超类可以轻松分解多个功能,因为所有功能所需的代码都相同。

但有时,特别是对于“解析”方法,我有 10 个类必须实现相同的算法,而另外 10 个类需要特定算法。

根据我对 python 的了解,这种行为可以通过使用 mixin 轻松分解。

但是即使“解析”算法相同,这里也存在问题,我需要将标签应用于解析的条目,并且该标签特定于每个类。我想知道这是否是使用仅由 mixin 使用的类属性来实现此目标的正确方法。

这段代码给出了如何使用属性的示例:

class MyMixin():
    def parse(self):
        print(self.tag)
        ...

class MyClass(MyMixin):
    tag = 'mytag'
Run Code Online (Sandbox Code Playgroud)

我已经在一些框架(http://www.django-rest-framework.org/api-guide/generic-views/)中看到了它,但我很想知道社区的意见。

==========================

编辑

用一个具体的例子来总结一下,我应该这样写:

class MyMixin():
    def do_something(self):
        print(self.tag)

class MyClass(MyMixin):
    tag = 'mytag'

if __name__ == '__main__':
    c = MyClass()
    c.do_something()
Run Code Online (Sandbox Code Playgroud)

或者那个 :

class MyMixin():
    def do_something(self, tag):
        print(tag)

class MyClass(MyMixin):
    tag = 'mytag'

if __name__ == '__main__':
    c = MyClass()
    c.do_something(c.tag)
Run Code Online (Sandbox Code Playgroud)

小智 8

您可以使用 mixins 在其他类中实现组合。通过这种方式,您可以将功能委托给 mixin 并在其他类中重用 mixin。因此,在使用 python 时,你对 mixin 有两个规则:

  • Mixin 类不应派生自任何基类(对象除外)
  • 但是他们可能假设他们将与之混合的类确实从某个基类派生出来,因此他们可能假设基类在那里,他们假设该类具有某些属性。

这两条规则将 mixin 与继承区分开来。

所以要回答你的问题,是的,你可以使用父属性,如果你确保父属性具有这些属性。

一个小例子(来自:https : //mail.python.org/pipermail/tutor/2008-May/062005.html):

class Base(object):
    """Base class for mixer classes. All mixin classes
    require the classes they are mixed in with to be
    instances of this class (or a subclass)."""

    def __init__(self,b):
        self.b = b # Mixin classes assume this attribute will be present

class MixinBPlusOne(object):
    """A mixin class that implements the print_b_plus_one
    method."""

    def __init__(self):
        print 'MixinBPlusOne initialising'

    def print_b_plus_one(self):
        print self.b+1

class MixinBMinusOne(object):
    """A mixin class that implements the print_b_minus_one
    method."""

    def __init__(self):
        print 'MixinBMinusOne initialising'

    def print_b_minus_one(self):
        print self.b-1

class Mixer(Base,MixinBPlusOne,MixinBMinusOne):
    """A mixer class (class that inherits some mixins), this
    will work because it also inherits Base, which the
    mixins expect."""

    def __init__(self,b):
        # I feel like I should be using super here because 
        # I'm using new-style classes and multiple
        # inheritance, but the argument list of
        # Base.__init__ differs from those of the Mixin
        # classes, and this seems to work anyway.
        Base.__init__(self,b)
        MixinBPlusOne.__init__(self)
        MixinBMinusOne.__init__(self)

class BrokenMixer(MixinBPlusOne,MixinBMinusOne):
    """This will not work because it does not inherit Base,
    which the mixins expect it to do."""

    pass

m = Mixer(9)
m.print_b_plus_one()
m.print_b_minus_one()

m = BrokenMixer(9)
m.print_b_plus_one() # It'll crash here.
Run Code Online (Sandbox Code Playgroud)

django restframework 示例也非常好:django rest framework mixins

  • Mixin 必须以相反的顺序放置:`class Mixer(MixinBPlusOne, MixinBMinusOne, Base):`。在这种情况下,Mixin 的顺序并不重要,但基类必须位于列表的最后。 (5认同)

Ale*_*all 5

您可以借助该abc模块获得一些额外的安全性:

from abc import abstractproperty, ABCMeta

class Parser(object):
    __metaclass__ = ABCMeta

    @abstractproperty
    def tag(self):
        pass

class Concrete(Parser):

    @property
    def tag(self):
        return 'concrete'

print Concrete().tag  # => prints 'concrete'

class Incomplete(Parser):
    pass

# Raises error:
# TypeError: Can't instantiate abstract class Incomplete with abstract methods tag
Incomplete()
Run Code Online (Sandbox Code Playgroud)

(Python 3 的代码可能略有不同)

这样,错误就可以尽早被捕获,而不是在访问属性时捕获。

此外,PyCharm 会警告该类的定义不完整。其他静态分析工具可能也可以解决这个问题。

在此输入图像描述