[Python-Dev] Metaclass insanity - another use case

Guido van Rossum guido@python.org
Tue, 05 Nov 2002 12:58:33 -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!

OK.  Setting __name__ to 'outer.inner' seems to be the best solution,
so I'll add that to my TODO list.  [SF bug #633930]

> 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.  :)

And I think there's nothing wrong with it -- it's a different use of
classes, but makes sense; it's a good use of nested namespaces (as
opposed to nesting helper classes inside the main class which they
help).

--Guido van Rossum (home page: http://www.python.org/~guido/)