我想知道在初始化实例后是否能够继承其中一个类。如下所示我有两个类 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())
答案 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
类的副本但具有不同基础的类型,或者它可能是一个基类为Child
和Outfit
的空类。Child
方法将Outfit
变为Outfit.__subclasscheck__
的“虚拟子类”。即使在Outfit
,Child
和child
都已创建之后,这也会有用。在这种情况下,虽然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
是每个方法的参数,而不是某些固定的非局部变量。