[Python-Dev] Metaclass insanity - another use case

Phillip J. Eby pje@telecommunity.com
Tue, 05 Nov 2002 12:49:39 -0500

I was reading the "metaclass insanity" thread this morning about dotted 
__name__ for nested classes, and I thought I should chime in that I've 
actually *used* this technique.  That is, I've had classes of the form:

class outer:
     class inner:

And then regenerated 'inner' such that inner.__name__ == 'outer.inner' and 
stored it in globals()['outer.inner'].  This *does* work with existing 
pickle code; in fact it worked as far back as Python 1.5.2!

As for *why* I had inner classes, the following might be a good example:

     class ModelElement(Element):

         class isSpecification(model.Field):
             isRequired = 1
             qualifiedName = 'Foundation.Core.ModelElement.isSpecification'
             _XMINames = ('Foundation.Core.ModelElement.isSpecification',)
             name = 'isSpecification'
             referencedType = 'Boolean'

         class stereotype(model.Reference):
             isNavigable = 0
             isRequired = 1
             _XMINames = ('Foundation.Core.ModelElement.stereotype',)
             name = 'stereotype'
             referencedType = 'Stereotype'
             refTypeQN = 'Foundation.Core.ModelElement.stereotype'
             referencedEnd = 'extendedElements'

This is a tiny excerpt from some automatically generated code which defines 
the UML 1.3 metamodel as a set of Python classes.  The nested classes 
represent structural features of the defined outer class, and enforce 
properties such as multiplicity, requiredness, etc., as you can see.

In an earlier version of this work, the inner classes had metaclasses whose 
__get__ method instantiated the inner class, and placed an instance in the 
outer object instance.  That is, each ModelElement instance would have a 
'stereotype' instance created on demand, which would manage the 
'stereotype' property.  And for this to be picklable, it was necessary for 
the inner classes to be accessible by the pickle machinery -- hence my use 
of qualified class names, as described above.

I will admit that I no longer use this approach for the inner classes; I 
found a way to get by without ever instantiating them.  The above code is 
still valid, but the metaclasses used are different.  So the pickling is 
simpler and faster.

I'm not sure if this is really an argument for or against, but at least 
it's actual usage.  :)