使用继承共享基础对象

时间:2012-12-10 10:52:57

标签: python inheritance python-3.x wrapper composition

我上课Base。我想在类Derived中扩展其功能。我打算写:

class Derived(Base):
  def __init__(self, base_arg1, base_arg2, derived_arg1, derived_arg2):
    super().__init__(base_arg1, base_arg2)
    # ...
  def derived_method1(self):
    # ...

有时我已经有一个Base实例,我想基于它创建一个Derived实例,即共享Derived对象的Base实例(不会从头开始重新创建它。我以为我可以写一个静态方法来做到这一点:

b = Base(arg1, arg2) # very large object, expensive to create or copy
d = Derived.from_base(b, derived_arg1, derived_arg2) # reuses existing b object

但似乎不可能。或者我错过了一种方法来完成这项工作,或者(更有可能)我错过了一个很大的原因,为什么它不能被允许工作。有人可以解释它是哪一个吗?

[当然,如果我使用构图而不是继承,这一切都很容易。但我希望避免将所有Base方法委托给Derived__getattr__。]

3 个答案:

答案 0 :(得分:2)

依靠Base课程与base_arg1base_arg2合作的内容。

class Base(object):
    def __init__(self, base_arg1, base_arg2):
        self.base_arg1 = base_arg1
        self.base_arg2 = base_arg2
        ...

class Derived(Base):
    def __init__(self, base_arg1, base_arg2, derived_arg1, derived_arg2):
        super().__init__(base_arg1, base_arg2)
        ...

    @classmethod
    def from_base(cls, b, da1, da2):
        return cls(b.base_arg1, b.base_arg2, da1, da2)

答案 1 :(得分:1)

Alexey的答案(我的+1)的替代方法是传递base_arg1参数中的基础对象并检查是否误用来传递基础对象(如果它是基类的实例)。其他agrument在技术上可以是可选的(比如None),并在代码中决定时明确检查。

不同之处在于只有参数类型决定了使用两种可能的创建方式。如果无法在源代码中显式捕获对象的创建,则这是必要的(例如,某些结构包含参数元组的混合,其中一些具有初始值,其中一些具有对现有对象的引用。然后您将可能需要将参数作为关键字参数传递:

d = Derived(b, derived_arg1=derived_arg1, derived_arg2=derived_arg2)

更新:为了与初始类共享内部结构,可以使用这两种方法。但是,您必须意识到,如果其中一个对象试图修改共享数据,通常会发生有趣的事情。

答案 2 :(得分:1)

这里要清楚,我会用代码回答。 pepr谈到了这个解决方案,但代码总是比英语更清晰。在这种情况下,Base不应该是子类,但它应该是Derived:

的成员
class Base(object):
    def __init__(self, base_arg1, base_arg2):
        self.base_arg1 = base_arg1
        self.base_arg2 = base_arg2

class Derived(object):
    def __init__(self, base, derived_arg1, derived_arg2):
        self.base = base
        self.derived_arg1 = derived_arg1
        self.derived_arg2 = derived_arg2

    def derived_method1(self):
        return self.base.base_arg1 * self.derived_arg1