【问题标题】:Selectively inherit in a child class in python在python的子类中选择性继承
【发布时间】:2019-09-25 01:41:45
【问题描述】:

我定义了以下类:

class First(object):
    def __init__(self):
        print("first")

    def mF1(self):
        print "first 1"

    def mF2(self):
        print "first 2"


class Second(object):
    def __init__(self):
        print("second")

    def mS1(self):
        print "second 1"


class Third(object):
    def __init__(self):
        print("third")

    def mT1(self):
        print "third 1"

    def mT2(self):
        print "third 2"

    def mT3(self):
        print "third 3"


class Fourth(First, Second, Third):
    def __init__(self):
        super(Fourth, self).__init__()
        print("fourth")


C = Fourth()
C.mF1()
C.mF2()
C.mS1()
C.mT1()
C.mT2()
C.mT3()

它给出了输出:

first
fourth
first 1
first 2
second 1
third 1
third 2
third 3

这样,很明显FirstSecondThirdFourth 类的所有属性和方法都在类Fourth 中可用。 现在,我希望 Fourth 类根据上下文选择性地从父级继承 - 即单独从 First 或从 FirstThird 等。一种方法是定义如下的单独类:

class Fourth1(First):
    def __init__(self):
        super(Fourth, self).__init__()
        print("fourth first")


class Fourth2(First, Third):
    def __init__(self):
        super(Fourth, self).__init__()
        print("fourth first third")

这意味着定义了单独的类,并且具有单独的类名而不是一个。

我想知道是否有更简单、动态和“pythonic”的方式来实现这一点?是否可以以简单的方式选择从哪里继承(就像super() 所做的那样,继承所有属性和方法,包括私有方法),比如,

C = Fourth(1,0,0)

First

继承
C = Fourth(1,0,1)

FirstThird 继承?

【问题讨论】:

  • 从所有类继承的类不适合你的需要,就像只从一两个继承的类吗?或者换句话说:if it quacks like a duck, it is a duck。如果它也能吠叫有什么关系?
  • @KlausD。我明白你的意思。但是如果代码库很大,有很多不需要的东西可能会给系统资源造成负担,不是吗?
  • 仅当您从那些“不需要的”类中运行代码时。
  • 注明。这很有启发性。

标签: python python-2.7 class inheritance multiple-inheritance


【解决方案1】:

可以通过__new__ 完成。因为可以动态创建类继承自其他类,而__new__可以创建任意类型的对象:

class Fourth(object):
    """BEWARE special class that creates objects of subclasses"""
    classes = [None] * 8

    def __new__(cls, first, second, third):
        index = 1 if first else 0
        index += 2 if second else 0
        index += 4 if third else 0
        if not cls.classes[index]:
            parents = [Fourth]
            if first: parents.append(First)
            if second: parents.append(Second)
            if third: parents.append(Third)
            ns = {'__new__': object.__new__,
                  '__init__': Fourth._child__init__,
                  '__doc__': Fourth.__doc__}
            cls.classes[index] = type('Fourth', tuple(parents), ns)
        return object.__new__(cls.classes[index])

    def _child__init__(self, first = None, second=None, third=None):
        Fourth.__init__(self)

    def __init__(self):
        print("Fourth")

之后你就可以做你想做的事了:

>>> c = Fourth(1,0,0)
Fourth
>>> c2 = Fourth(1,1,1)
Fourth
>>> c
<__main__.Fourth1 object at 0x0000024026151780>
>>> c2
<__main__.Fourth7 object at 0x000002402616E8D0>
>>> c2.mT1()
third 1
>>> c.mT1()
Traceback (most recent call last):
  File "<pyshell#302>", line 1, in <module>
    c.mT1()
AttributeError: 'Fourth1' object has no attribute 'mT1'

但我强烈建议您不要使用这种 hack,除非您有重要的理由这样做。因为它最终有一个类 (Fourth),它不是从自身创建对象,而是从子类创建对象。显然属于该类的对象将具有不同的行为。这会打扰未来的读者和维护者

【讨论】:

  • 好的。这看起来很令人满意。所以,你也建议像@Klaus D. 那样从所有父类继承作为安全的赌注,而不是这样实现?
  • @skrowten_hermit:实现这种方式很有趣。但我永远不会在生产级代码中使用它。我找不到真正的原因,所以我同意 Klaus 的观点:通过类创建的对象应该属于该类,因此从所有父类继承会更安全(也更容易维护)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-11
  • 1970-01-01
  • 1970-01-01
  • 2020-11-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多