Create a class at run-time

Peter Otten __peter__ at web.de
Fri Mar 26 15:16:28 EDT 2010


Michel wrote:

> Thanks Peter.
> 
> I searched a little bit more and wrote the following example:
> 
> ------------------------------------
> import types
> 
> class MyClass:
> 
>     def test_toto(self):
>         print type(self)
>         print self.name
> 
> def test_toto(self):
>     print type(self)
>     print self.name
> 
> MyDynClass = types.ClassType("MyDynClass", (object, ), {})
> MyDynClass.__module__ = "test.complex.hierarchy"
> MyDynClass.test_toto = test_toto
> 
> t1 = MyDynClass()
> t2 = MyDynClass()
> 
> t1.name = "Marcel"
> t2.name = "Oscar"
> 
> t1.test_toto()
> t2.test_toto()
> 
> c1 = MyClass()
> c1.name = "Raoul"
> c1.test_toto()
> --------------------------------
> 
> the output is:
> 
> <class 'test.complex.hierarchy.MyDynClass'>
> Marcel
> <class 'test.complex.hierarchy.MyDynClass'>
> Oscar
> <type 'instance'>
> Raoul
> 
> I'm wondering why the type of the self parameter is not 'instance' in
> the calls
> t1.test_toto() and t2.test_toto()
> 
> The rest of the behavior is correct though, so I guess it's just
> internal Python stuff.

In Python 2.x there are "classic" and "newstyle" classes. In practice the 
main differences are that classic classes are more likely to call 
__getattr__() and that only newstyle classes support properties correctly.

By inheriting from object you make MyDynClass a newstyle class:

>>> classic = types.ClassType("A", (), {})
>>> newstyle = types.ClassType("A", (object,), {})

>>> type(classic()), type(classic)
(<type 'instance'>, <type 'classobj'>)

>>> type(newstyle()), type(newstyle)
(<class '__main__.A'>, <type 'type'>)

Classic classes exist for backwards compatibility and because most 
programmers are too lazy to have their classes inherit from object when the 
difference doesn't matter. When you create a class dynamically I recommend 
that you use the type() builtin instead of types.ClassType(). This will 
always create a newstyle class -- even when you don't inherit from object 
explicitly:

>>> type(type("A", (), {}))
<type 'type'>
>>> type("A", (), {}).__bases__
(<type 'object'>,)

Peter




More information about the Python-list mailing list