我有一个模块(db.py),它从不同的数据库类型(sqlite,mysql等)加载数据。该模块包含一个类db_loader和继承自它的子类(sqlite_loader,mysql_loader)。
正在使用的数据库类型位于单独的params文件中,
用户如何获得正确的对象?
即我该怎么做:
loader = db.loader()
我是否在db.py模块中使用一个名为loader的方法,或者是否有一种更优雅的方法,即类可以根据参数选择自己的子类?有没有标准的方法来做这种事情?
答案 0 :(得分:6)
听起来你想要Factory Pattern。您可以定义一个工厂方法(在您的模块中,或者可能在它可以生成的所有对象的公共父类中),并将参数传递给它,它将返回正确类的实例。在python中,问题比维基百科文章中的一些细节要简单一些,因为你的类型是动态的。
class Animal(object):
@staticmethod
def get_animal_which_makes_noise(noise):
if noise == 'meow':
return Cat()
elif noise == 'woof':
return Dog()
class Cat(Animal):
...
class Dog(Animal):
...
答案 1 :(得分:2)
我将子类的名称存储在params文件中,并且有一个工厂方法,可以根据其名称实例化该类:
class loader(object):
@staticmethod
def get_loader(name):
return globals()[name]()
class sqlite_loader(loader): pass
class mysql_loader(loader): pass
print type(loader.get_loader('sqlite_loader'))
print type(loader.get_loader('mysql_loader'))
答案 2 :(得分:2)
将类存储在dict
中,根据您的参数实例化正确的类:
db_loaders = dict(sqlite=sqlite_loader, mysql=mysql_loader)
loader = db_loaders.get(db_type, default_loader)()
其中db_type
是您要启用的参数,sqlite_loader
和mysql_loader
是“加载程序”类。
答案 3 :(得分:1)
是否有一种更优雅的方式可以使类根据参数选择自己的子类?
您可以通过重写基类的__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
。
如果您也有孙子类,那么我建议将子类的集合放到一个递归类方法中,该方法将每个谱系都放在末尾,并添加所有后代。
此解决方案比工厂方法模式恕我直言更漂亮。与其他答案不同,它是自维护的,因为子类列表是动态创建的,而不是保存在硬编码的映射中。而且,这只会实例化子类,这与其他答案之一不同,后者会实例化全局命名空间中与给定参数匹配的任何内容。