0

In C, if I want to define a type from a name I could use the preprocessor. For example,

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

And then I could define a concrete struct like so

DEFINE_STRUCT(Useless);

and use the Useless struct like this

struct MyUseslessStruct instance;

So my question is

  • Is there a way to achieve this in Python?

I have the following 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)

For each ClassName the contents of items will be different, so I would like something like

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)

I don't want to repeat the code over and over, I would like to generate it if possible.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97

2 Answers2

4

You're very close:

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

As you can see, you define it using a placeholder name, then assign its __name__ attribute. After that, you return it so you can then use it as you desire in your client code. Remember, a Python class is an object just as much as any other, so you can return it, store it in a variable, put it into a dictionary, or whatever you like once you've defined it.

The __name__ attribute is a convenience, mainly so error messages make sense. You may not actually need to give each class a unique name.

An alternative for this particular use case might be to use 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 = []

By not defining items on the base class, you ensure that you must subclass it and define a per-class items to actually use the class.

kindall
  • 178,883
  • 35
  • 278
  • 309
  • Interesting, I used the `__name__` member for other things in other classes, but I never thought I could assign to it. Exactly what I was looking for. – Iharob Al Asimi Apr 14 '15 at 03:11
  • So the `items` variable will be diferente each time I call this fuction even if I pass the same `name`? – Iharob Al Asimi Apr 14 '15 at 03:18
  • 1
    Yes. Class (and function) definitions are *executed* in Python. So each time you call the function, you get a new class. You can check their `id()` to be sure.. Of course, you could just use subclasses... – kindall Apr 14 '15 at 03:19
1

kindall's answer is very clear and likely preferable, but there is a built-in function to generate classes: type. When called with one argument, it returns the type of an object. When called with three arguments it generates a new type/class. The arguments are class name, base classes, and the class 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': [] })
axblount
  • 2,639
  • 23
  • 27