有没有更优雅的方式让类可以根据参数选择自己的子类?
您可以通过覆盖基类的__new__ 方法来做到这一点。这将允许您简单地转到loader = db_loader(db_type) 和loader 将神奇地 成为数据库类型的正确子类。这个解决方案比其他答案稍微复杂一些,但恕我直言,它肯定是最优雅的。
最简单的形式:
class Parent():
def __new__(cls, feature):
subclass_map = {subclass.feature: subclass for subclass in cls.__subclasses__()}
subclass = subclass_map[feature]
instance = super(Parent, subclass).__new__(subclass)
return instance
class Child1(Parent):
feature = 1
class Child2(Parent):
feature = 2
type(Parent(1)) # <class '__main__.Child1'>
type(Parent(2)) # <class '__main__.Child2'>
(注意只要__new__返回一个cls的实例,就会自动为你调用实例的__init__方法。)
这个简单的版本虽然有问题,需要扩展和定制以适应您想要的行为。最值得注意的是,这是您可能想要解决的问题:
Parent(3) # KeyError
Child1(1) # KeyError
所以我建议将cls 添加到subclass_map 或将其用作默认值,例如subclass_map.get(feature, cls)。如果您的基类不打算被实例化——也许它甚至有抽象方法? -- 那么我建议给Parent 元类abc.ABCMeta。
如果您也有孙类,那么我建议将子类的集合放入递归类方法中,该方法遵循每个沿袭到最后,添加所有后代。
这个解决方案比工厂方法模式恕我直言更漂亮。与其他一些答案不同,它是自我维护的,因为子类列表是动态创建的,而不是保存在硬编码映射中。而且这只会实例化子类,不像其他答案之一,它将实例化与给定参数匹配的全局命名空间中的任何内容。