Pythonic多重继承生成自定义类集合

2024-04-26 06:22:50 发布

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

我的Python代码中有两个类树:

       BaseComponent                      BaseSeries
      /      |      \                          |
Resistor Capacitor Inductor                 ESeries

BaseSeries类树实现首选数,例如E-series,并生成一对幂之间的值集(例如,对于指数在1到3之间的E3序列,[1.0, 2.2, 4.7, 10, 22, 47, 100, 220, 470])。你知道吗

默认情况下,ESeriesBaseSeries的任何其他实例创建float对象序列。我想使用这些类来创建ResistorCapacitorInductor对象序列。理想情况下,单独的ResistorCapacitorInductorESeries类将保持其自身的可用性(即,不依赖于由其他类实现的方法)。你知道吗

这听起来像是一个多重继承的工作,但我有点困惑如何在Python(3)中最好地实现它。理想情况下,我只想定义如下:

class ResistorESeries(Resistor, ESeries):
    pass

class CapacitorESeries(Capacitor, ESeries):
    pass

class InductorESeries(Inductor, ESeries):
    pass

为了创建产生电阻器、电容器和电感器序列的类,但是我不知道如何最好地告诉BaseSeries实例来创建类型为ResistorCapacitorInductor的对象。我能想到两种方法,但我不能决定哪一种是最好的,我有一种感觉,有一种更简单,更具Python的方法,我错过了:

  1. 具有BaseSeries包含指向由构造函数、子类中的类变量(例如Resistor.ELEMENT_TYPE = Resistor)或子类提供的抽象属性设置的元素类型(例如Resistor)的属性或变量:

    class BaseSeries(object):
        ...
        def elements(self):
            # loop over numbers in this series
            for v in self.values():
                yield self.element_type(v)
    
        @property
        @abc.abstractmethod
        def element_type(self):
            return NotImplemented
    
    class ESeries(BaseSeries):
        ....
    
    class BaseComponent(object):
        ...
        @property
        def element_type(self):
            return self
    
    class Resistor(BaseComponent):
        ...
    
    class ResistorESeries(Resistor, ESeries):
        # now BaseSeries' `element_type` property is provided by `BaseComponent`
        pass
    

    这意味着ESeries不能单独用作具体的对象,因为它没有实现这个不理想的属性/变量。

  2. BaseSeries中创建元素时使用self,其中self将引用所需元素,只要Resistor位于方法解析顺序的前面:

    class BaseSeries(object):
        ...
        def elements(self):
            # loop over numbers in this series
            for v in self.values():
                # self here would refer to `Resistor` in
                # `ResistorESeries` instances
                yield self(v)
    
    class ESeries(BaseSeries):
        ....
    
    class BaseComponent(object):
        ...
    
    class Resistor(BaseComponent):
        ...
    
    class ResistorESeries(Resistor, ESeries):
        pass
    

这样做的缺点是,在ESeries的实例中,没有用作mix-in,self将引用自身,它不支持正确的__init__签名。你知道吗

那么,有没有人知道如何以一种Pythonic的方式最好地做到这一点,并且能够最大限度地重用自己的类?你知道吗


Tags: 对象方法inselfobject序列passclass
1条回答
网友
1楼 · 发布于 2024-04-26 06:22:50

您可能在这里混合了一些概念——特别是“实例”和“类”——您的示例调用确实很复杂。你知道吗

我无法从您的设计中理解为什么BaseComponent树上的类需要沿着BaseSeries树继承:组件类型不能只是BaseSeries类上的一个属性吗?你知道吗

这只是使用class属性的问题,在您第一次尝试时建议的代码中,使用一个平淡无奇的if语句。你知道吗

class BaseSeries:
   component = None

    def elements(self):
        # loop over numbers in this series
        for v in self.values():
            yield self.component(v) if self.component else v

class Capacitor(BaseComponent):
   ...


class CapacitorSeries(BaseSeries):
   component = Capacitor

如果你认为你需要多重继承,你可以按照你的想法使用一个属性,并在那里使用相同的“If”语句。但是如果这两个层次结构都是这样的,我不明白为什么要强制使用多重继承,仅仅因为语言允许。你知道吗

也许您更喜欢另一种方式:组件树上的工厂方法,它将把一个ESeries类作为输入,并从中提取值。。。你知道吗

不管怎么说,您并没有弄清楚类和实例的区别。您是否需要一种方法来生成
的几个子类 “电容器系列”,每个等级的值不同? 或者你只需要“电容器”的实例,每一个都有不同的价值产生的系列?你知道吗

class BaseComponent:
    ...
    @classmethod
    def series_factory(self, series):
          for value in series.values():
                yield self.__class__(value)

当然,对于您声明的所有内容,可能都需要类的用例,包括一系列类的工厂,但是您在代码片段中使用self作为可调用项,这表明您对此的立场并不坚定。你知道吗

在这种情况下,首先,您需要所有方法来正确使用super。即使它们不应该跨两个层次结构存在,使用super也只会调用超类上的适当方法。但是对于像__init__这样的方法,这只是需要的。你知道吗

如果您使用super设计一个合适的__init__方法,并且总是使用命名参数,那么您的第二个策略将开箱即用,只需修复实例化调用(对self(v)以外的对象)。使用命名参数并将剩余的参数传递给super将确保树中的每个类都使用这些参数所需的内容—当Python到达层次结构的根并调用object__init__时,就没有剩余的参数了

class BaseSeries:
    def __init__(self, value_min, value_max, **kwargs):
         self.value_min = value_min
         selfvalue_max = value_max
         super().__init__(**kwargs)

    def elements(self):
        # loop over numbers in this series
        for v in self.values():
            yield self.__class__(value_min = self.value_min, value_max=self.value_max, value=value)

class BaseComponent:
    def __init__(self, value, **kwargs):
         self.value = value

...

class CapacitorESeries(Capacitor, Eseries):
    pass

相关问题 更多 >