Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>FYI, the accepted terminology used when nesting classes as you've done is inner/outer, not parent/child or super/subclass. The parent/child or super/sub relationship refers to inheritance. This makes your decorator's name, <code>setsubclasses</code>, confusing, since there are no subclasses involved!</p> <p>The unusual thing you're doing here is using the class as a namespace without instantiating it. Normally you would <em>instantiate</em> your <code>ComponentModel</code> and at that time, it is trivial to give your <code>Serialiser</code> inner class a copy of an attribute from its outer class. E.g.:</p> <pre><code>class ModelBase(object): def __init__(self): self.Serialiser.origin = self.origin # ... then cm = ComponentModel() ser = cm.Serialiser() </code></pre> <p>Better yet, have the outer class instantiate the inner class and pass it a reference to the outer class; then it can grab any attributes it wants itself, whenever it needs them:</p> <pre><code>class ModelBase(object): def __init__(self, *args, **kwargs): serialiser = self.Serialiser(self, *args, **kwargs) class SerialiserBase(LibrarySerialiser): def __init__(self, outer, *args, **kwargs): self.outer = outer print self.outer.origin super(SerialiserBase, self).__init__(*args, **kwargs) # ... cm = ComponentModel() ser = cm.serialiser </code></pre> <p>However, if you insist on being able to get this attribute without instantiating the outer class, you can use a metaclass to set the attribute:</p> <pre><code>class PropagateOuter(type): def __init__(cls, name, bases, dct): type.__init__(cls, name, bases, dct) if "Serialiser" in dct: cls.Serialiser.outer = cls class ModelBase(object): __metaclass__ = PropagateOuter # Python 3 version of the above # class ModelBase(metaclass=PropagateOuter): # pass class SerialiserBase(LibrarySerialiser): def __init__(self, *args, **kwargs): print self.outer.origin super(SerialiserBase, self).__init__(*args, **kwargs) class ComponentModel(ModelBase): origin = 'supermarket' class Serialiser(SerialiserBase): pass ser = ComponentModel.Serialiser() </code></pre> <p>This isn't doing anything your decorator isn't, but the user gets it automatically through inheritance rather than having to specify it manually. The Zen of Python says "explicit is better than implicit" so tomato, tomato.</p> <p>You could even write the metaclass so that it introspects the outer class and puts a reference to that class into <em>every</em> inner class regardless of their name.</p> <p>By the way, one of the pitfalls of the way you're doing this is that all your model classes <em>must</em> subclass <code>SerialiserBase</code>. If a user of your class just wants the default serialiser, they can't just write <code>Serialiser = SerialiserBase</code> in their class definition, they <em>must</em> write <code>class Serialiser(SerialiserBase): pass</code>. This is because there's only one <code>SerialiserBase</code> and it obviously can't contain a reference to <em>multiple</em> outer classes. Of course, you could write your metaclass to deal with this (e.g. by automatically making a subclass of the specified serialiser if it already has an <code>outer</code> attribute). </p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload