【问题标题】:Init super with existing instance?用现有实例初始化超级?
【发布时间】:2020-04-27 10:56:59
【问题描述】:

假设我有:

class Super:
  def __init__(self,a):
     self.a = a
  @classmethod
  def from_b(cls,b):
     return cls(b.to_a())

class Regular(Super):
   def __init__(self,b):
      # how to set my super to the output of
      super = super.from_b(b)

如何使用超类方法的输出而不是 init 来正确初始化超类?

我的 OOP 背景是 C++,由于能够在 C++ 中重载构造函数,我不断地进入这些场景,所以解决这个问题会很棒。

【问题讨论】:

  • 我认为最自然的做法是class Regular(Super): pass,然后使用现有接口从bs 创建实例:Regular.from_b(b)

标签: python python-3.x inheritance constructor super


【解决方案1】:

这有点尴尬(因为您尝试做的事情有点尴尬),但它会起作用:

class Super:
  def __init__(self,a):
     self.a = a
  @classmethod
  def from_b(cls,b):
     return cls(b.to_a())

class Regular(Super):
   def __init__(self,b):
      a = Super.from_b(b).a
      super().__init__(a)

顺便说一句,记住 from_b() 之类的“构造函数”方法(通常)返回一个新对象可能会有所帮助,而 __init__()初始化 em> 创建后的对象。

【讨论】:

  • 哦哈哈,解决了。
  • 对于更大的数据结构,是否会产生额外的开销? (比如复制?)还是控制移动了?
  • 这里唯一可能复制数据的部分是to_a() 方法,必须调用,并且在此解决方案中只调用一次。
  • 好的,太棒了。我发现 python 实际上保持相当快(不能真正称之为快速)......只要你尽量避免复制
  • @donlan 避免复制并不难,因为 Python 本质上从不隐式复制。要复制对象,您必须显式复制它。
【解决方案2】:

@shx2 的答案有效,但浪费/尴尬地创建了一个废弃的Super 对象,只是为了用其a 属性初始化新的Regular 对象。

如果您可以控制Super 的来源,您可以让from_b 方法创建给定子类的实例,并让子类在其__new__ 方法中调用from_b 方法,所以Regular 对象可以直接创建和初始化:

class Super:
    def __init__(self, a):
        self.a = a

    @classmethod
    def from_b(cls, b):
        obj = super().__new__(cls)
        cls.__init__(obj, b.to_a())
        return obj

class Regular(Super):
    def __new__(cls, b):
        return super().from_b(b)

这样下面的断言就会通过:

from unittest.mock import Mock

obj = Regular(Mock())
assert type(obj) is Regular
assert obj.a.to_a.is_called()

【讨论】:

    猜你喜欢
    • 2019-10-12
    • 1970-01-01
    • 2020-11-08
    • 1970-01-01
    • 2015-05-24
    • 1970-01-01
    • 1970-01-01
    • 2017-02-06
    • 2015-06-28
    相关资源
    最近更新 更多