如何在Python中动态定义一个type/class?

How to define a type/class in Python dynamically?

C 中,如果我想根据名称定义类型,我可以使用预处理器。例如,

#define DEFINE_STRUCT(name)        \
    struct My##name##Struct        \
     {                             \
        int integerMember##name;   \
        double doubleMember##name; \
     }

然后我可以像这样定义一个具体的结构

DEFINE_STRUCT(Useless);

并像这样使用 Useless 结构

struct MyUseslessStruct instance;

所以我的问题是

我有以下class

class ClassName(SQLTable):
    items = []
    def __init__(self, value):
        SQLTable.__init__(self)
        # some common code
        if value in self.items:
            return
        self.items.append(value)

对于每个ClassNameitems的内容会有所不同,所以我想要

def defineclass(ClassName):
    class <Substitute ClassName Here>(SQLTable):
        items = []
        def __init__(self, value):
            SQLTable.__init__(self)
            # some common code
            if value in self.items:
                return
            self.items.append(value)

我不想一遍又一遍地重复代码,如果可能我想生成它。

你非常接近:

def defineclass(ClassName):
    class C(SQLTable):
        items = []
        def __init__(self, value):
            SQLTable.__init__(self)   
            # some common code
            if value in self.items:
                return
            self.items.append(value)
    C.__name__ = ClassName
    return C

如您所见,您使用占位符名称定义它,然后分配其 __name__ 属性。之后,你 return 它这样你就可以在你的客户端代码中随意使用它。请记住,Python class 与任何其他对象一样都是一个对象,因此您可以 return 它,将其存储在变量中,将其放入字典或任何您喜欢的东西一次你已经定义了它。

__name__ 属性很方便,主要是让错误消息有意义。您实际上可能不需要给每个 class 一个唯一的名称。

此特定用例的替代方法可能是使用 subclassing:

class Base(SQLTable):
    def __init__(self, value):
        SQLTable.__init__(self)   
        # some common code
        if value in self.items:
            return
        self.items.append(value)

class Thing1(Base): items = []
class Thing2(Base): items = []

通过不在基础 class 上定义 items,您确保必须子class 它并定义一个 per-class items 到实际上 使用 class.

kindall 的回答非常清楚并且可能更可取,但是有一个内置函数可以生成 classes:type。当使用一个参数调用时,它 returns 对象的类型。当使用三个参数调用时,它会生成一个新的 type/class。参数是 class 名称、基础 classes 和 class 字典。

def custom_init(self, value):
    SqlTable.__init__(self)
    if value in self.items:
        return
    self.items.append(value)

def defineclass(classname):
    #           __name__   __bases__    __dict__
    return type(classname, (SQLTable,), { '__init__': custom_init,
                                          'items': [] })