如何动态定义Python中的类型/类?

时间:2015-04-14 03:02:08

标签: python c c-preprocessor code-generation

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

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

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

DEFINE_STRUCT(Useless);

并使用像这样的Useless结构

struct MyUseslessStruct instance;

所以我的问题是

  • 有没有办法在Python中实现这个目标?

我有以下课程

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)

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

2 个答案:

答案 0 :(得分:4)

你非常接近:

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__属性。之后,您将其返回,以便您可以根据需要在客户端代码中使用它。请记住,Python类是一个对象,就像任何其他对象一样,所以你可以return它,将它存储在一个变量中,把它放到一个字典中,或者你定义它之后的任何你喜欢的东西。

__name__属性是一种方便,主要是错误消息有意义。您实际上可能不需要为每个类赋予唯一的名称。

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

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 = []

通过不在基类上定义items,您确保必须对其进行子类化并定义每个类items以实际使用该类。

答案 1 :(得分:1)

kindall的答案非常明确,可能更可取,但有一个内置函数可以生成类:type。当使用一个参数调用时,它返回一个对象的类型。当使用三个参数调用时,它会生成一个新类型/类。参数是类名,基类和类dict。

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': [] })