

Dynamically create a type with Python - henryprecheur
http://henry.precheur.org/2009/6/17/Dynamically_create_a_type_with_Python.html

======
daeken
Good little introduction in terms of general use, but I think a solid example
is in order, as it's a very useful technique.

A while back, I created a Struct class, which allows the creation of C-like
structs, but you had to create a subclass of Struct, specify the endianness as
a class attribute, and create a __format__ method that built the struct
members. A little while ago, I had the thought to wrap it into a decorator,
defStruct/defStructLE/defStructBE, that automagickly calls 'type' to build the
appropriate Struct class for you, given a method.

So what once was:

    
    
        class Foo(Struct):
          __endian__ = Struct.LE
          def __format__(self):
            self.foo = Struct.uint32
            self.bar = Struct.string(self.foo)
    

Became:

    
    
        @defStructLE
        def Foo(self):
          self.foo = Struct.uint32
          self.bar = Struct.string(self.foo)
    

Much, much cleaner, all thanks to the magic of 'type'.

~~~
lehmannro
I'd rather utilize a metaclass in this special case. This would retain the
notion of Foo being a type much better than transmogrifying a function into a
class. (Granted, there's not that big a difference technically but you're
tricking other programmers into believing Foo cannot be used for eg.
isinstance.)

    
    
      class Foo(Struct):
        __endian__ = Struct.LE
        foo = Struct.uint32
        bar = Struct.string(foo)
    

If you don't like specifying the endianness as a class attribute you could
still inherit from Struct.LE/BE rather than Struct itself.

Quick technical howto: make Struct have a __metaclass__ class attribute,
populate the __metaclass__ class with a __new__ or __init__ method performing
the desired transformations.

See
[http://www.python.org/download/releases/2.2/descrintro/#meta...](http://www.python.org/download/releases/2.2/descrintro/#metaclasses)
for details on metaclasses.

~~~
daeken
Metaclasses won't fly in this case, since the order of struct members has to
be kept. Tried a bunch of things to make it work, but in the end nothing came
out cleaner.

~~~
jbox
"Metaclasses won't fly in this case, since the order of struct members has to
be kept."

Couldn't you use a creation counter in a metaclasses and assign order to the
attributes as they are added? (like Django's forms use to keep track of field
order)

~~~
lehmannro
Oh, I didn't think about the order. Django's approach to this issue is really
simple and only requires that all your Struct fields are instances of some
common base class.

[http://code.djangoproject.com/browser/django/trunk/django/fo...](http://code.djangoproject.com/browser/django/trunk/django/forms/fields.py#L97)
creation of the counter on individual fields

[http://code.djangoproject.com/browser/django/trunk/django/fo...](http://code.djangoproject.com/browser/django/trunk/django/forms/forms.py#L37)
application of the counter upon field harvesting

------
mortenoffline
If he wanted to persist the classes offered by the server you could actually
write the python code to a module, reload module and import the class proper.
Did that a while ago so I didn't have to restart a daemon all the time.

