如何从基类动态创建派生类

例如,我有一个如下的基类:

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')

Is there a nice, pythonic way to create those classes dynamically by a function call that puts the new class into my current scope, like:

foo(BaseClass, "My")
a = MyClass()
...

由于会有注释和问题,我为什么需要这样做: 派生类都具有完全相同的内部结构,只是存在差异,即构造函数接受许多以前未定义的参数。例如,MyClass接受关键字 a,而类 TestClass的构造函数接受 bc

inst1 = MyClass(a=4)
inst2 = MyClass(a=5)
inst3 = TestClass(b=False, c = "test")

But they should NEVER use the type of the class as input argument like

inst1 = BaseClass(classtype = "My", a=4)

我得到了这个工作,但更喜欢其他方式,即动态创建的类对象。

102615 次浏览

type() 是创建类特别是子类的函数,就像问题中提到的:

def set_x(self, value):
self.x = value


# type() takes as argument the new class name, its base
# classes, and its attributes:
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

这段代码允许您创建具有动态 names and parameter names. __init__中的参数验证不允许 未知参数,如果需要其他验证,比如 类型,或者它们是强制的,只需添加逻辑 那里:

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", "a b c".split())
>>> s = SpecialClass(a=2)
>>> s.a
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

我看到您要求在命名范围中插入动态名称—— 现在,那个在 Python 中并不被认为是一个好的实践——您也可以 变量名,在编码时已知,或数据-和名称在运行时学习 更多的是“数据”而不是“变量”-

所以,你可以把你的类添加到一个字典中,然后从那里开始使用它们:

name = "SpecialClass"
classes = {}
classes[name] = ClassFactory(name, params)
instance = classes[name](...)

And if your design absolutely needs the names to come in scope, 只是做同样的,但使用字典返回的 globals() 调用而不是任意的字典:

name = "SpecialClass"
globals()[name] = ClassFactory(name, params)
instance = SpecialClass(...)

(类工厂函数确实有可能在调用者的全局作用域上动态插入名称——但这是更糟糕的做法,而且不能在 Python 实现之间兼容。这样做的方法是通过 Sys _ getframe (1)获取调用者的执行框架,并在框架的全局字典中的 f_globals属性中设置类名)。

这个答案已经变得流行起来了,但是它仍然非常特定于问题的主体。关于如何 “从基类动态创建派生类” 在 Python 中,对 type的简单调用传递了新的类名、带有基类(es)的元组和新类的 __dict__主体,如下所示:

>>> new_class = type("NewClassName", (BaseClass,), {"new_method": lambda self: ...})

更新
任何需要这个的人也应该检查 莳萝项目-它声称能够 pickle 和 unpickle 类,就像 pickle 对普通对象所做的那样,并且在我的一些测试中已经实现了。

To create a class with a dynamic attribute value, checkout the code below. 注意,这是 Python 中的代码片段

def create_class(attribute_data, **more_data): # define a function with required attributes
class ClassCreated(optional extensions): # define class with optional inheritance
attribute1 = adattribute_data # set class attributes with function parameter
attribute2 = more_data.get("attribute2")


return ClassCreated # return the created class


# use class


myclass1 = create_class("hello") # *generates a class*

就我而言:

inst3 = globals()["SpecialClass"](b=False, c = "test")