8

I am working with an ORM that accepts classes as input and I need to be able to feed it some dynamically generated classes. Currently, I am doing something like this contrived example:

def make_cls(_param):
   def Cls(object):
       param = _param
   return Cls

A, B = map(make_cls, ['A', 'B'])

print A().foo
print B().foo

While this works fine, it feels off by a bit: for example, both classes print as <class '__main__.Cls'> on the repl. While the name issue is not a big deal (I think I could work around it by setting __name__), I wonder if there are other things I am not aware of. So my question is: is there a better way to create classes dynamically or is my example mostly fine already?

hugomg
  • 68,213
  • 24
  • 160
  • 246
  • Possible duplicate of http://stackoverflow.com/questions/4513192/python-dynamic-class-names – cEz Feb 10 '12 at 20:56
  • 3
    As Roman notes below, you will want to use `type` to dynamically create classes. The top answer in [this question](http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python) covers this in very good detail. – aganders3 Feb 10 '12 at 20:57
  • "An ORM"? Which ORM? Odds are good the ORM does much of this for you. – S.Lott Feb 10 '12 at 21:24
  • @S.Lott: I'm playing with sqlalchemy. Anyway, I think the origin of the issue is not in the ORM but actually in me deciding it would be overall simpler to use a bunch of tables with similar schemas instead of bundling them in a single table. – hugomg Feb 10 '12 at 21:51
  • Why would you need to create a "dynamically generated class"? Does your database design have tables which are created dynamically? – S.Lott Feb 10 '12 at 22:00
  • Oh, its not really that "dynamic" - it runs when I'm loading the DB and I happen to have some tables that share the same schema. – hugomg Feb 10 '12 at 22:20
  • Multiple tables in one schema is not a problem. I don't get why creating "dynamically generated class" is even relevant. – S.Lott Feb 10 '12 at 22:34
  • @S.Lott: That is probably just me abusing the ORM a bit :) I want to create a separate entity and relationships for each of those tables. – hugomg Feb 10 '12 at 22:56
  • That's the way it works out of the box. I don't get why the ordinary SQLAlchemy is not working for you. – S.Lott Feb 10 '12 at 22:58
  • Are you looking for this? http://docs.sqlalchemy.org/en/latest/orm/extensions/sqlsoup.html – S.Lott Feb 10 '12 at 22:59

1 Answers1

10

What is class? It is just an instance of type. For example:

>>> A = type('A', (object,), {'s': 'i am a member', 'double_s': lambda self: self.s * 2})
>>> a = A()
>>> a
<__main__.A object at 0x01229F50>
>>> a.s
'i am a member'
>>> a.double_s()
'i am a memberi am a member'

From the doc:

type(name, bases, dict)

Return a new type object. This is essentially a dynamic form of the class statement.

Roman Bodnarchuk
  • 29,461
  • 12
  • 59
  • 75
  • Since type is only receiving these 3 parameters, am I safe to assume that the name was really the only thing that was going wrong or are there other advantages to using `type` too? – hugomg Feb 10 '12 at 21:00
  • 1
    A nice way to package this is to wrap it in a function that takes keyword arguments, so you can easily specify the attributes of the new class in the function call. – kindall Feb 10 '12 at 21:03
  • @missingno Well, you approach would be useful while creating some complex classes (for example, addition of `classmethod` with usage of `type` would be ugly), but if you need to build some complex in runtime, then probably something really bad happened to your architecture :) `type` is just recommended solution for such things. – Roman Bodnarchuk Feb 10 '12 at 21:08