在创建为实例后,类如何从另一个类继承

时间:2018-03-30 21:42:57

标签: python

我想知道在初始化实例后是否能够继承其中一个类。如下所示我有两个类 Child 和'Outfit',并在创建一个实例后作为 child 。我希望它继承自 Outfit 类,所以我可以使用函数get_cloth返回蓝色。出于某种原因,我不希望Child从Outfit类继承

class Outfit(object):
    def __init__(self):
        self.cloth = 'blue' if self.gender == 'M' else 'red'

    def get_cloth(self):
        return self.cloth

class Child:
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

child = Child('tom', 'M')
print(child.get_cloth())

3 个答案:

答案 0 :(得分:3)

做你想做的事是没有意义的。对象不继承,只有类型。实例child的类型可以继承(是其子类型)另一种类型,但该类型为Child,并且您说您不希望Child继承自Outfit {1}}。

对于任何面向对象的编程语言来说,这都不是必须的。相反,它是基于类的OO(Python,Ruby,Smalltalk,C ++,Java等)和基于原型的OO(JavaScript,Self,IO和其他一些您从未听说过的语言)之间的根本区别。

你可以做的一些事情与你所要求的有些接近,但它们都是你很少想做的事情。

如果您对子类型感兴趣,那就是isinstance(child, Outfit)为真:

  • 您可以将Child更改为在Outfit创建后继承(例如,通过设置其__mro__属性)。甚至可以在创建child实例之后。然后,child现在将成为子类型Outfit
  • 的实例
  • 您可以在创建后将child的类型更改为不同的类型(通过设置其__class__属性)。但是你仍然需要创建一些Outfit子类型的类型。也许是一个Child类的副本但具有不同基础的类型,或者它可能是一个基类为ChildOutfit的空类。
  • 您可以通过定义Child方法将Outfit变为Outfit.__subclasscheck__的“虚拟子类”。即使在OutfitChildchild都已创建之后,这也会有用。在这种情况下,虽然isinstance(child, Outfit)会通过,但它实际上并不像Outfit那样行事;你只是在愚弄isinstance。或者,换一种方式,你得到名义上的子类型而没有行为子类型。
  • 您可以child成为Outfit的“虚拟实例”,而无需通过定义Child方法将Outfit.__instancecheck__变为虚拟子类。
  • 您可以构建一个Prototype元类,它可以有效地平滑类和类的实例之间的区别,而是为您提供类似Self或JavaScript对象模型的东西。这是很多工作,你的Prototype类在与“普通”类进行交互时会做一些奇怪的事情,但它是可行的。完成后,您可以根据需要修改child的原型链。

如果您只对继承行为感兴趣 - 不仅仅是Outfit打字,而是让Outfit为您完成工作 - 这是最简单的方法那就是忘记类型,只需将Outfit实例组成child并转发。但不幸的是,这并不像听起来那么容易:

  • 您可以定义__getattr__。但实际上不会为child.spam调用{仅仅getattr(child, 'spam');只有类型的__getattr__才能正常成员访问。如果这很重要(几乎可以肯定),您需要构建一个新类型并重新分配__class__,如前所述。
  • 您可以迭代Outfit或组合outfit实例的所有方法,并将转发(绑定)方法显式添加到child。但是只有一小部分特殊方法会查看实例而不是类。因此,虽然child.spam()可行,但child + 2却不会。如果这是一个问题(通常是,但不像上一个案例那么普遍),您仍然需要构建一个新类型并重新分配__class__

无论如何,所有这些都是可能的,因为它们偶尔会有用,但它们都不容易,因为它们几乎总是错误的。 (如果你确定你想要做任何一个,并且从文档中如何做到这一点并不明显,并且这里没有另一个问题可以解释如何,创建一个新问题,清楚地解释你想要哪一个要做和为什么。)

答案 1 :(得分:0)

通过让Child故意传递未知属性,您可以更安全地做到这一点:

class Outfit(object):
    def __init__(self, child_self):
        self.cloth = 'blue' if child_self.gender == 'M' else 'red'

    def get_cloth(self):
        return self.cloth

class Child:
    def __init__(self, name, gender):
        self.super_self = None
        ...

    def __getattr__(self, name):
        if self.super_self is None:
            raise AttributeError(name)
        else:
            return getattr(self.super_self , name)

child = Child(...)

child.super_self = Outfit(child)
print(child.get_cloth())  # Should work now

答案 2 :(得分:0)

如前面的答案中所述,在实例级而不是类级别应用继承的概念没有多大意义。如果您真正想要的只是child可以访问get_cloth的{​​{1}}方法,则可以明确指定:

Outfit

请注意,我使用child = Child('tom', 'M') child.get_cloth = Outfit().get_cloth print(child.get_cloth()) 而非Outfit().get_cloth来提取Outfit.get_cloth作为一种方法而不只是作为一种功能。

这很容易实现,这取决于Python语言的设计选择,即get_cloth是每个方法的参数,而不是某些固定的非局部变量。