I often find I have class instances that are descendants of other class instances, in a tree like fashion. For example say I'm making a CMS platform in Python. I might have a Realm, and under that a Blog, and under that a Post. Each constructor takes it's parent as the first parameter so it knows what it belongs to. It might look like this:
class Realm(object):
def __init__(self, username, password)
class Blog(object):
def __init__(self, realm, name)
class Post(object);
def __init__(self, blog, title, body)
I typically add a create method to the parent class, so the linkage is a bit more automatic. My Realm class might look like this:
class Realm(object):
def __init__(self, username, password):
...
def createBlog(self, name):
return Blog(self, name)
That allows the user of the API to not import every single module, just the top level one. It might be like:
realm = Realm("admin", "FDS$#%")
blog = realm.createBlog("Kittens!")
post = blog.createPost("Cute kitten", "Some HTML blah blah")
The problem is those create methods are redundant and I have to pydoc the same parameters in two places.
I wonder if there's a pattern (perhaps using metaclasses) for linking one class instance to a parent class instance. Some way I could call code like this and have the blog know what it's parent realm is:
realm = Realm("admin", "FDS$#%")
blog = realm.Blog("Kittens!")
You could use a common base class for the containers featuring an add()
method
class Container(object):
def __init__(self, parent=None):
self.children = []
self.parent = parent
def add(self, child)
child.parent = self
self.children.append(child)
return child
and make the parent
parameter optional in the derived classes
class Blog(Container):
def __init__(self, name, realm=None):
Container.__init__(realm)
self.name = name
Your code above would now read
realm = Realm("admin", "FDS$#%")
blog = realm.add(Blog("Kittens!"))
post = blog.add(Post("Cute kitten", "Some HTML blah blah"))
You wouldn't have any create...()
methods any more, so no need to document anything twice.
If setting the parent involves more than just modifying the parent
attribute, you could use a property or a setter method.
EDIT: As you pointed out in the comments below, the children should be tied to the parents by the end of the contstructor. The above approach can be modified to support this:
class Container(object):
def __init__(self, parent=None):
self.children = []
self.parent = None
def add(self, cls, *args)
child = cls(self, *args)
self.children.append(child)
return child
class Realm(Container):
def __init__(self, username, password):
...
class Blog(Container):
def __init__(self, realm, name):
...
class Post(Container):
def __init__(self, blog, title, body):
...
realm = Realm("admin", "FDS$#%")
blog = realm.add(Blog, "Kittens!")
post = blog.add(Post, "Cute kitten", "Some HTML blah blah")
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