【问题标题】:Python class interdependenciesPython 类相互依赖
【发布时间】:2018-12-08 12:05:38
【问题描述】:

我有一个 python 类,它作为更多子类的基类。它包含一个应该作用于所有子类相同的方法,例如我想把它放在基类中。问题是,这个方法应该返回子类的一个新实例。但是我由于基类位于子类的定义之前,我无法创建子类的新实例,因为它在基类的范围内是未知的:

class Base:
  def __init__(self, value):
    self.value = value

  def convert_child_classes(self, newclass):
    newvalue = MakeUsableInNewclass(self.value)
    newattr = MakeUsableInNewclass(self.subclassattr)
    return newclass(newattr, newvalue)


class Child1(Base):
  def __init__(self, subclassattr, value)
    super(Child, self).__init__(value)
    self.subclassattr = subclassattr

  def MethodForSubClassAttr(self):
    ...do sth with self.subclassattr...


class Child2(Base):
  def __init__(self, subclassattr, value)
    super(Child, self).__init__(value)
    self.subclassattr = subclassattr

  def SomeOtherSubClassAttrMethod(self):
    ...do sth that is related to this class attr...

如果我有 Child1 的实例,我希望能够对其数据进行一些处理,然后在调用 convert_child_classes(Child2) 时返回具有新值的 Child2 的实例:

A = Child1('someattr', 5)
B = A.convert_child_classes(Child2)

现在 B 应该是 Child2 的一个实例,其值是从 Child1 计算出来的。但由于 Base 类现在知道 Child1 或 Child2 是什么,它无法启动新类。

【问题讨论】:

  • @Torilla 你到底在说什么?因为如果您使用来自Child1 的属性,那么您可以直接从Base Class 操作它们而不会出现问题。关于实例化Class2,您可以接收Child2 作为参数,就像您已经做的那样,但是当您return newclass(newvalue) 时,您应该从Child2 __init__ 函数中添加两个参数,这里没有显示它
  • 思路是baseclass的子类很多,但是它们是相互关联的,可以相互转换。举一个实际的例子,想想一个代表长度的基类,一个代表米的子类和一个代表码和一英寸的子类。例如,如果我有一个代表 5 米的实例,我希望能够将其转换为 Inch 类。
  • 完美!因此,您应该使用一个指标作为您的BaseClass 的参考。现在,对于每个Child 实例,创建一个变量,例如self.conversion,它将存储两个指标之间的转换值。现在,当您调用convert_child_classes 时,在分配给new class 之前进行计算,使用所有类都将实现的self.conversion,因此您无需关心它来自哪个类。这对你有意义吗?
  • 但是如果我调用 Child2(newattr, newvalue) 我会得到一个 ValueError 因为 BaseClass des 不知道 Child2 是什么。
  • 我倾向于这样做:(1)​​定义一些规范的基本单位(2)每个类都知道如何将自己转换为基本单位(3)每个类都有一个工厂类方法,它接受其他类,调用其convert_to_base_unit 方法,然后根据该值创建自身的实例。

标签: python class inheritance class-structure


【解决方案1】:

我遇到了你的问题:
1.实际上你在super中使用Child是错误的,因为它应该是你正在操作的类的名称,在这种情况下Child1或Child2。
2.我将 Base 添加为一个抽象类,以确保它不会被实例化(正如我从你的问题中得到的那样)。
3. 由于方法MakeUsableInNewClass 是强制实现的,我将添加为abstractmethod 以确保在子类上实现。

所以正确的代码是:

from abc import ABC, abstractmethod
class Base(ABC):
    def __init__(self, value):
        self.value = value

    def convert_child_classes(self, newclass):
        newvalue, newattr = self.MakeUsableInNewclass()
        return newclass(newattr, newvalue)

    @abstractmethod
    def MakeUsableInNewclass(): pass

class Child1(Base):
    def __init__(self, subclassattr, value):
        super(Child1, self).__init__(value)
        self.subclassattr = subclassattr

    def MakeUsableInNewclass(self):
        newvalue = self.value #do operations
        newattr = self.subclassattr #do operations
        return newvalue, newattr

class Child2(Base):
    def __init__(self, subclassattr, value):
        super(Child2, self).__init__(value)
        self.subclassattr = subclassattr

    def MakeUsableInNewclass(self):
        newvalue = self.value #do operations
        newattr = self.subclassattr #do operations
        return newvalue, newattr

【讨论】:

    【解决方案2】:

    这样的东西应该可以工作(未经测试):

    class Measurement:
    
        @classmethod
        def from_other(cls, other):
            base = other.convert_to_base_unit()
            converted = cls.base_to_unit(base)
            return cls(converted)
    
        @classmethod
        def base_to_unit(cls, value):
            # Let the subclass implement this
            raise NotImplementedError
    
        def convert_to_base_unit(self):
            # Let the subclass implement this
            raise NotImplementedError
    

    以这种方式实现,基类不需要知道任何关于子类的信息。基类提供模板方法(from_other),子类提供实现。

    【讨论】:

      猜你喜欢
      • 2011-09-18
      • 1970-01-01
      • 1970-01-01
      • 2013-09-03
      • 2011-04-26
      • 2017-05-09
      • 1970-01-01
      • 2013-10-21
      • 1970-01-01
      相关资源
      最近更新 更多