我如何dynamic地从基类创build派生类
例如,我有一个基类,如下所示:
class BaseClass(object): def __init__(self, classtype): self._type = classtype
从这个类我得到几个其他类,例如
class TestClass(BaseClass): def __init__(self): super(TestClass, self).__init__('Test') class SpecialClass(BaseClass): def __init__(self): super(TestClass, self).__init__('Special')
有没有一种很好的pythonic方法来创build这些类dynamic的一个函数调用,把新类放入我的当前范围,如:
foo(BaseClass, "My") a = MyClass() ...
因为会有评论和问题,为什么我需要这样的:派生类都有完全相同的内部结构与差异,构造函数采取了一些以前未定义的参数。 因此,例如, MyClass
将类关键字a
作为类TestClass
的构造函数接受b
和c
。
inst1 = MyClass(a=4) inst2 = MyClass(a=5) inst3 = TestClass(b=False, c = "test")
但是他们绝不应该使用类的types作为input参数
inst1 = BaseClass(classtype = "My", a=4)
我得到这个工作,但宁愿其他的方式,即dynamic创build类对象。
这一小段代码允许你用dynamic名称和参数名称创build新的类。 在__init__
的参数validation只是不允许未知的参数,如果你需要其他的validation,如types,或者他们是强制性的,只是在那里添加逻辑:
class BaseClass(object): def __init__(self, classtype): self._type = classtype def ClassFactory(name, argnames, BaseClass=BaseClass): def __init__(self, **kwargs): for key, value in kwargs.items(): # here, the argnames variable is the one passed to the # ClassFactory call if key not in argnames: raise TypeError("Argument %s not valid for %s" % (key, self.__class__.__name__)) setattr(self, key, value) BaseClass.__init__(self, name[:-len("Class")]) newclass = type(name, (BaseClass,),{"__init__": __init__}) return newclass
而且这个工作是这样的,例如:
>>> SpecialClass = ClassFactory("SpecialClass", "abc".split()) >>> s = SpecialClass(a=2) >>> sa 2 >>> s2 = SpecialClass(d=3) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 8, in __init__ TypeError: Argument d not valid for SpecialClass
我看到你正在要求在命名范围中插入dynamic名称 – 现在,在Python中这不被认为是一种好的做法 – 你可以有在编码时已知的variables名或数据 – 而在运行时学到的名称更“数据“比”variables“ –
所以,你可以把你的类添加到字典中,并从那里使用它们:
name = "SpecialClass" classes = {} classes[name] = ClassFactory(name, params) instance = classes[name](...)
如果你的devise绝对需要这个名字的话,只需要使用globals()
调用返回的字典而不是一个任意的字典:
name = "SpecialClass" globals()[name] = ClassFactory(name, params) instance = SpecialClass(...)
(实际上类工厂函数可以在调用者的全局范围内dynamic地插入名字 – 但这是更糟糕的做法,并且在Python实现中是不兼容的。要做到这一点的方法是获取调用者的执行框架,通过sys._getframe(1)并在框架的全局字典中的f_globals
属性中设置类名称)。
更新,tl;博士:这个答案已经变得stream行起来,对于问题主体来说还是很具体的。 关于如何在Python中“从基类dynamic创build派生类”的一般答案是一个简单的调用,用于传递新类名称,一个带有基类的元组和一个新的类的__dict__
主体,就像这样:
>>> new_class = type("NewClassName", (BaseClass,), {"new_method": lambda self: ...})
更新
任何人都需要这个应该也检查莳萝项目 – 它声称能够泡菜和unpickle类像腌菜对普通物体,并已经住在我的一些testing。
type()
是创build类(特别是子类)的函数:
def set_x(self, value): self.x = value SubClass = type('SubClass', (BaseClass,), {'set_x': set_x}) # (More methods can be put in SubClass, including __init__().) obj = SubClass() obj.set_x(42) print obj.x # Prints 42 print isinstance(obj, BaseClass) # True