Me again! Same project as before, if you're playing along at home. The Everything Engine model (which I am blatantly copying in my project) is that everything in the engine is a 'node,' and that every node can be stored to and read from the database. Since this is the backend for a website, minimizing hits on the database is a worthy goal. Thus, it is paramount that reading in any given subclass of the base 'Node' class take (optimally) one query. (A simple, yet fairly simple-minded design -- and my first stab at the problem -- would be to have each subclass read in its own data after calling its parent's -- or parents'! -- read method(s). This has the disadvantage of cluttering a lot of code with database queries and making it quite difficult to create new subclasses.)
Here's a rough sketch of what I'm doing at the moment. I've invested enough time into it at this point that I've totally lost track of whether it's a good idea, and I would please like someone to tell me. Every node has certain attributes. In this outline, let's say these are the node's unique id number, its title, and the id number of its owner. class Node: dbInfo = { 'title' : ['node', 'title', ""] 'owner_id' : ['node', 'owner_id', None] } def __init__(self): self.default() def default(self): self.node_id = None for k, v in self.dbInfo.items(): setattr(self, k, v[2]) def read(self, db, node_id): # construct a database query from the table/column info in # dbInfo def commit(self, db): # write the current values to the db def insert(self, db): # insert a new node using the current values def nuke(self, db): # remove the node from the db, then: self.default() So, simple enough. (The real version has signifigantly more stuff going on, as well as a permission system, but I have elided these for the sake of clarity.) By doing that dance with dbInfo, I can easily subclass Node. Say we want a new node that holds some text. We just need to add a new attribute like so: class Document(Node): dbInfo = {} dbInfo.update(Node.dbInfo) dbInfo['content'] = ['docs', 'text', ""] ... and that's it. That's the whole Document class. (Well, the real version has a render method that takes the content, parses it in interesting ways, and writes it to the client, but that's simple, too.) The shortness of this class is why this strikes me as a good idea. The other advantage is I can make use of multiple inheritance. First, say we have a class that just holds a dictionary: class DictNode(Node): dbInfo = {} dbInfo.update(Node.dbInfo) dbInfo['stuff'] = ['dictnode', 'dict', {}] (Assume a mechanism is provided to automatically pickle the dictionary, which there is.) Now say I want a nodetype that's just a document with a dictionary attached. This is almost exactly how the User class is implemented: the document holds the user's "homenode," which is just a brief bio or whatever the user wants to put in there, and the dictionary holds the user's settings. They snap together like Legos. It looks just like this: class User(Document, DictNode): dbInfo = {} dbInfo.update(Document.dbInfo) dbInfo.update(DictNode.dbInfo) If the User class wanted its own attributes (say, a password), they would just get added to the end. This is my third stab at the problem (the first was mentioned above, the second was basically the same as this but dbInfo was an instance variable instead of a class variable which, uh, was sort of dumb). Coming from C++, I'm still wrapping my brain around Python's introspection abilties. Can I generalize this more? Am I missing some idiom or language feature that would benefit me? Where's my time machine? -Kirk McDonald -- http://mail.python.org/mailman/listinfo/python-list