我怎么能动态地从一个基类派生创建类(How can I dynamically create der

2019-07-21 02:18发布

例如我有一个基类,如下所示:

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采用bc

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

但是他们不应该使用这个类的类型,就像输入参数

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

我得到这个工作,但宁愿另一种方式,即动态创建的类对象。

Answer 1:

这段代码可以让你创建新类具有动态名称和参数名称。 参数核查__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传递新的类名,与基类(ES)和一个元组__dict__体为新类样的:

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

更新
任何人都需要这也应该检查萝项目-它声称能够咸菜和unpickle类就像泡菜确实给普通对象,并一直住到它在我的一些测试。



Answer 2:

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


文章来源: How can I dynamically create derived classes from a base class