Python 如何从基类动态创建派生类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15247075/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I dynamically create derived classes from a base class
提问by Alex
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:
是否有一种很好的 Pythonic 方法可以通过将新类放入我当前范围的函数调用来动态创建这些类,例如:
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, MyClasstakes the keywords awhile the constructor of class TestClasstakes band c.
因为会有评论和问题,为什么我需要这个:派生类都具有完全相同的内部结构,不同之处在于构造函数采用许多以前未定义的参数。因此,例如,当类的构造函数采用and时MyClass采用关键字。aTestClassbc
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.
我让它工作,但更喜欢另一种方式,即动态创建的类对象。
采纳答案by jsbueno
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:
这段代码允许您创建具有动态名称和参数名称的新类。中的参数验证__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
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, thatis 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" -
我看到您要求在命名范围中插入动态名称 - 现在,这在 Python 中不被认为是一个好的做法 - 您要么拥有在编码时已知的变量名称,要么拥有数据 - 而在运行时学习的名称更多”数据”而不是“变量”-
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:
如果您的设计绝对需要名称进入范围,只需执行相同操作,但使用globals()调用返回的字典而不是任意字典:
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_globalsattribute).
(类工厂函数确实可以在调用者的全局范围内动态插入名称 - 但这是更糟糕的做法,并且在 Python 实现之间不兼容。这样做的方法是获取调用者的执行框架,通过sys._getframe(1)并在其f_globals属性中设置框架全局字典中的类名)。
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 typepassing the new class name, a tuple with the baseclass(es) and the __dict__body for the new class -like this:
更新,tl;dr:这个答案已经变得流行,但它仍然非常特定于问题主体。关于如何
在 Python 中“从基类动态创建派生类”的一般答案
是type传递新类名的简单调用,一个带有基类的元组和__dict__新类的主体 - 像这样:
>>> new_class = type("NewClassName", (BaseClass,), {"new_method": lambda self: ...})
update
Anyone needing this should also check the dillproject - 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.
更新
任何需要这个的人也应该检查dill项目 - 它声称能够像 pickle 对普通对象一样对类进行 pickle 和 unpickle,并且在我的一些测试中已经做到了。
回答by Eric O Lebigot
type()is the function that creates classes (and in particular sub-classes):
type()是创建类(特别是子类)的函数:
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
回答by AdefemiGreat
To create a class with a dynamic attribute value, checkout the code below. NB. This are code snippets in python programming language
要创建具有动态属性值的类,请查看下面的代码。注意。这是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*

![Python 如何避免[Errno 12] 使用子进程模块导致无法分配内存错误](/res/img/loading.gif)