如何在python中参数化mixin,而不显式调用它们的构造函数?

2024-09-27 22:40:07 发布

您现在位置:Python中文网/ 问答频道 /正文

我想在python中更多地使用mixin,比如:

class Person:
  [...]

class Greetable:
  greeting: str

  def __init__(*args, **kwargs):
    super().__init(*args, **kwargs)
    ... greeting related setup

  def greet(self):
    print(f"{self.greeting} sir or madam!")

class Sailor(Greetable, Person):
  def __init__(self):
    super().__init__()

    self.greeting = "Ahoy"

>>> Sailor().greet()
"Ahoy sir or madam!"

但我还没有解决参数化混合的问题。在我的工作中,我看到很多对超类的显式__init__调用á

class A(B, FloorMixin):
  def __init__(desk, chair, floor):
    B.__init__(self, desk, chair)
    FloorMixin.__init__(floor)

我看到了分解参数并显式分发它们的用法,但是我希望保留上述Mixin示例的__init__所具有的“passthrough”属性

我只能考虑将Mixin的所有参数作为特定的关键字参数,这些参数从**kwargs参数中得到pop,或者只依赖Mixin中存在的字段,并且必须在之前设置它们,这将把最后一个示例变成:

class A(FloorMixin, B):
  def __init__(desk, chair, floor):
    self._floor = floor  # FloorMixin expects a _floor attribute

    super().__init__(desk, chair)

Tags: self参数initdefmixinkwargsclassgreeting
1条回答
网友
1楼 · 发布于 2024-09-27 22:40:07

正确使用super的关键是,层次结构中涉及的每个类都应该假定其他所有类也将调用super。除了object之外的所有类都是这样,它总是任何继承层次结构中的根类

以你为例

class A(B, FloorMixin):
  def __init__(self, desk, chair, floor):
    B.__init__(self, desk, chair)
    FloorMixin.__init__(floor)

这意味着ABFloorMixin都应该调用super().__init__,并且在实例化A时应该使用关键字参数,以便不存在基于顺序的冲突

class B:
    def __init__(self, desk, chair, **kwargs):
        super().__init__(**kwargs)
        # Do stuff with desk and chair

class FloorMixin:
    def __init__(self, floor, **kwargs):
        super().__init__(**kwargs)
        # Do stuff with floor

class A(B, FloorMixin):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # If there's nothing else to do, you don't
        # even need to define A.__init__

# With keyword arguments, order doesn't matter
# Each __init__ will find the arguments it needs
# and pass on the rest
a = A(floor="...", chair="...", desk="...")

A的方法解析顺序是[A, B, FloorMixin, object],因此对super().__init__的每个调用都从行中的下一个类调用__init__A.__init__调用B.__init__,后者调用FloorMixin.__init__,后者调用object.__init__。重要的是,请注意,这意味着在运行时B.__init__调用一个类的__init__,而B的作者可能根本不知道这个类。这就是为什么重要的是接受意外的关键字参数并传递它们

相关问题 更多 >

    热门问题