如何从一个基类动态创建派生类 [英] How can I dynamically create derived classes from a base class
问题描述
例如,我有一个基类如下:
class BaseClass(object):
def __init __ self,classtype):
self._type = classtype
类,例如
class TestClass(BaseClass):
def __init __(self):
super ,self).__ init __('Test')
class SpecialClass(BaseClass):
def __init __(self):
super(TestClass,self).__ init __ )
有一个很好的python方法通过一个函数调用来动态创建这些类, class into我当前的范围,如:
foo(BaseClass,My)
a = MyClass $ b ...
由于会有注释和问题,为什么我需要:具有完全相同的内部结构与差异,构造函数采取一些以前未定义的参数。因此,例如 MyClass
使用关键字 a
,而类 TestClass
需要
b
和 c
。
inst1 = MyClass(a = 4)
inst2 = MyClass(a = 5)
inst3 = TestClass(b = False,c =test)
但是他们不应该使用类作为输入参数,如
inst1 = BaseClass(classtype =My,a = 4)
我得到这个工作,但更喜欢其他方式,即动态创建类对象。
这一段代码允许你使用动态
名称和参数名称创建新类。
在 __ init __
中的参数验证只是不允许
未知参数,如果您需要其他验证,如
类型,强制性,只需添加逻辑
:
class BaseClass(object):
def __init __ ,classtype):
self._type = classtype
def ClassFactory(name,argnames,BaseClass = BaseClass):
def __init __(self,** kwargs):
for key,kwargs.items()中的值:
#这里,argnames变量是传递给
的一个变量#ClassFactory调用
如果key不在argnames中:
raise TypeError(Argument%s对%s无效
%(key,self .__ class __.__ name__))
setattr(self,key,value)
BaseClass .__ init __ [:-len(Class)])
newclass = type(name,(BaseClass,),{__ init__:__init__})
return newclass
<$ c $> c>>>>> SpecialClass = ClassFactory(SpecialClass,a b c.split())
>>> s = SpecialClass(a = 2)
>>>> s.a
2
>>>> s2 = SpecialClass(d = 3)
回溯(最近一次调用):
在< module>中第1行的文件< stdin&
文件< stdin>,第8行,在__init__
TypeError:参数d对于SpecialClass无效
我看到你要求在命名范围中插入动态名称 -
现在, 在Python中不被认为是一个好的做法 - 你有
在编码时已知的变量名或在运行时学习的数据和名称
比变量更多的数据 -
,您只需将您的类添加到字典并从中使用:
name =SpecialClass
= {}
classes [name] = ClassFactory(name,params)
instance = classes [name](...)
如果你的设计绝对需要在范围内的名字,
只是做同样的,但使用globals()
调用而不是任意字典:name =SpecialClass
globals()[name] = ClassFactory(name,params)
instance = SpecialClass(...)
(类工厂函数确实可以插入名称动态地在调用者的全局范围 - 但是这是更糟的做法,并且不是在Python实现兼容。这样做的方式是通过 sys._getframe(1),并在其
f_globals
属性中的框架全局字典中设置类名。)
update,tl; dr:这个答案已经变得流行,它仍然对问题的身体非常具体。关于如何
的动态创建派生类的基本类
在Python中的一般回答是一个简单的调用type
传递新类名,一个带有基类的元组和用于新类的__ dict __
正文:>>> new_class = type(NewClassName,(BaseClass),{new_method:lambda self:...})
$ b b更新
任何需要此功能的用户还应查看 dill project - 它声称能够pickle和unpickle类,就像pickle对普通对象,并在我的一些测试生活。For example I have a base class as follows:
class BaseClass(object): def __init__(self, classtype): self._type = classtype
From this class I derive several other classes, e.g.
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() ...
As there will be comments and questions why I need this: The derived classes all have the exact same internal structure with the difference, that the constructor takes a number of previously undefined arguments. So, for example,
MyClass
takes the keywordsa
while the constructor of classTestClass
takesb
andc
.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)
I got this to work but would prefer the other way, i.e. dynamically created class objects.
解决方案This bit of code allows you to create new classes with dynamic names and parameter names. The parameter verification in
__init__
just does not allow unknown parameters, if you need other verifications, like type, or that they are mandatory, just add the logic there: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
And this works like this, for example:
>>> 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
I see you are asking for inserting the dynamic names in the naming scope -- now, that is not considered a good practice in Python - you either have variable names, known at coding time, or data - and names learned in runtime are more "data" than "variables" -
So, you could just add your classes to a dictionary and use them from there:
name = "SpecialClass" classes = {} classes[name] = ClassFactory(name, params) instance = classes[name](...)
And if your design absolutely needs the names to come in scope, just do the same, but use the dictionary returned by the
globals()
call instead of an arbitrary dictionary:name = "SpecialClass" globals()[name] = ClassFactory(name, params) instance = SpecialClass(...)
(It indeed would be possible for the class factory function to insert the name dynamically on the global scope of the caller - but that is even worse practice, and is not compatible across Python implementations. The way to do that would be to get the caller's execution frame, through sys._getframe(1) and setting the class name in the frame's global dictionary in its
f_globals
attribute).update, tl;dr: This answer had become popular, still its very specific to the question body. The general answer on how to "dynamically create derived classes from a base class" in Python is a simple call to
type
passing the new class name, a tuple with the baseclass(es) and the__dict__
body for the new class -like this:>>> new_class = type("NewClassName", (BaseClass), {"new_method": lambda self: ...})
update
Anyone needing this should also check the dill project - it claims to be able to pickle and unpickle classes just like pickle does to ordinary objects, and had lived to it in some of my tests.这篇关于如何从一个基类动态创建派生类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!