Say I have a class BigObject, which contains within it a number of SmallObjects - and this is the only place where SmallObject is used.
class SmallObject:
pass
class BigObject:
def __init__(self):
self.objects = [SmallObject() for _ in range(10)]
This is all fine, until I want a second version of these two, which inherits some behaviour and overrides some; inheritance seems natural, except:
class NewSmallObject(SmallObject):
pass
class NewBigObject(BigObject):
def __init__(self):
super().__init__()
self.objects = [NewSmallObject for _ in range(10)]
We had to create a bunch of SmallObjects only to immediately override them with NewSmallObjects. Which is not great if e.g. SmallObjects are expensive to create. Also, if we change how the list of SmallObjects is created in BigObject, those changes don't get passed on to NewBigObject.
The solution I came up with was to use nested classes:
class BigObject:
class SmallObject:
pass
def __init__(self):
self.objects = [self.SmallObject() for _ in range(10)]
class NewBigObject(BigObject):
class SmallObject(BigObject.SmallObject):
pass
This deals with both the issues described above. My main concern is that when I looked on StackOverflow for questions about nested classes in Python people keep saying nested classes are unpythonic, and I'd like to understand why. It can also create quite deeply nested classes if SmallObject contains TinyObjects which contain MinisculeObjects etc, which may be the answer?
So my question is basically:
is this a "good" solution to this problem?
if not, what would a good alternative be?
The solution is, as you've already found, to make SmallObject an attribute of the BigObject class.
There is nothing inherently wrong with using a nested class for this, but the readability of your code may suffer if the nested class is very long. Generally speaking, I would recommend to define SmallObject in the global scope though. After all, the Zen of Python says "Flat is better than nested". If you keep nesting TinyObjects and MinisculeObjects, your code will quickly become unreadable:
class BigObject:
class SmallObject:
class TinyObject:
class MinisculeObject:
... # MinisculeObject class body
... # TinyObject class body
... # SmallObject class body
... # BigObject class body
Defining your classes in the global scope only requires minimal extra effort, and looks much cleaner:
class MinisculeObject:
... # MinisculeObject class body
class TinyObject:
miniscule_object_factory = MinisculeObject
... # TinyObject class body
class SmallObject:
tiny_object_factory = TinyObject
... # SmallObject class body
class BigObject:
small_object_factory = SmallObject
... # BigObject class body
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With