我将首先编写代码,而不是我想要实现的完整解释,因为这样更容易:
global child_selector
class Base(object):
def __init__(self):
self.extended_name = self.name + '_Base'
class Child1(Base):
def __init__(self):
super(Child1, self).__init__()
def print_my_name(self):
print 'I am ChildOne'
class Child2(Base):
def __init__(self):
super(Child2, self).__init__()
def print_my_name(self):
print 'I am ChildTwo'
class ChildAsBaseSelector(object):
def __new__(cls):
if child_selector == 1:
return Child1()
elif child_selector == 2:
return Child2()
else:
print 'No child selected'
现在,如果我创建一个继承自Child1或Child2的类并将self.name作为实例变量,那么一切都按预期工作:
class Testing1(Child1):
def __init__(self):
self.name = 'Testing1'
super(Testing1, self).__init__()
a = Testing1()
a.print_my_name() # 'I am ChlidOne'
print a.extended_name # 'Testing1_Base'
但是,如果我创建另一个将直接从ChildAsBaseSelector()继承的类,那么事情就变得可疑:
class Testing2(ChildAsBaseSelector):
def __init__(self):
self.name = 'Testing2'
super(Testing2, self).__init__()
child_selector = 1
a = Testing2()
# Will raise AttributeError: 'Child1' object has no attribute 'name'
在阅读'__new __()'的python文档后,我认为问题是因为:'如果__new __()没有返回cls的实例,那么将不会调用新实例的__init __()方法。这并没有真正帮助,因为我不知道如何“修复它”。
我也知道我可以这样做:
if child_selector == 1:
ChildAsBaseSelector = Child1
if child_selector == 2:
ChildAsBaseSelector = Child2
而不是直接从ChildAsBaseSelector继承。但我发现这不是优雅的,并且将python灵活性推向极限。 我真正想做的是有一个类,它将根据条件返回另一个类,然后我可以使用它来继承。任何提示?我想metaclasses(我痛苦地试图理解的一个概念)现在会派上用场。
任何提示赞赏。谢谢!
答案 0 :(得分:0)
为什么不让ChildAsBaseSelector
继承Base
?在您的示例中,super(Testing2, self).__init__()
将解析为object.__init__()
(因此它不会按预期执行),但是 - 正如您所提到的 - 它无论如何都不会被调用,因为它不在{{1并非__mro__
和Child1
。
无论如何:让你的Child2
取决于在调用Base.__init__()
之前设置属性的子类是不好的设计 - 如果super().__init__()
需要它,那么它应该作为参数传递或在Base
本身具有可用的默认值。
此外,如果Base
的唯一存在理由是根据全局/设置/其他内容创建ChildAsBaseSelector
或Child1
的实例,只需使用工厂函数即可。没有“新”关键字真的是一种祝福。