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

2024-05-18 04:28:09 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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)

我让它工作,但更喜欢另一种方式,即动态创建类对象。


Tags: self参数objectinitmydefmyclass基类
3条回答

要创建具有动态属性值的类,请签出下面的代码。 注意。这是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*

这段代码允许您使用 名称和参数名称。 __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](...)

如果你的设计绝对需要名字的话, 也可以,但是使用^{}返回的字典 调用而不是任意字典:

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

(类工厂函数确实有可能在调用者的全局范围内动态插入名称——但这是更糟糕的做法,并且在Python实现中不兼容。方法是通过sys._getframe(1)获取调用方的执行框架,并在框架的全局字典的f_globals属性中设置类名。

更新,tl;dr:这个答案已经流行起来,仍然是对问题体非常特殊的。关于如何 “从基类动态创建派生类” 在Python中,简单地调用type传递新类名、一个包含基类的元组和新类的__dict__体,如下所示:

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

更新
任何需要这个的人都应该检查dill项目——它声称能够像pickle对普通对象那样对类进行pickle和unpickle操作,并且在我的一些测试中也经历过。

^{}是创建类(尤其是子类)的函数:

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

相关问题 更多 >