例如,我有一个基类如下:
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方法可以通过函数调用动态创建这些类,该函数调用将新类放入当前范围,如:
foo(BaseClass, "My")
a = MyClass()
...
因为我会需要这样的注释和问题:派生类都具有完全相同的内部结构,区别在于构造函数采用了许多以前未定义的参数。因此,例如,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)
我让这个工作,但更喜欢另一种方式,即动态创建的类对象。
答案 0 :(得分:116)
这段代码允许您使用动态创建新类
名称和参数名称。
__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](...)
如果你的设计绝对需要名字进入范围,
只是这样做,但使用globals()
返回的字典
调用而不是任意字典:
name = "SpecialClass"
globals()[name] = ClassFactory(name, params)
instance = SpecialClass(...)
(类工厂函数确实可以在调用者的全局范围内动态插入名称 - 但这更糟糕的做法,并且在Python实现中不兼容。这样做的方法是通过sys._getframe(1)获取调用者的执行帧,并在其f_globals
属性中设置框架全局字典中的类名。
更新,tl;博士:这个答案已经变得很受欢迎,对问题正文仍然非常具体。一般答案如何
“从基类动态创建派生类”
在Python中简单调用type
传递新的类名,一个带有基类的元组和一个用于新类的__dict__
体 - 就像这样:
>>> new_class = type("NewClassName", (BaseClass,), {"new_method": lambda self: ...})
<强>更新强>
任何需要这个的人都应该检查dill项目 - 它声称可以像pickle一样对普通对象进行pickle和unpickle类,并且在我的一些测试中已经活过了。
答案 1 :(得分:73)
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
答案 2 :(得分:-1)
要创建具有动态属性值的类,请签出以下代码。 注意这是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*