Update this project:
User:
Pass:
Title:
News:
Category:
Generally, I do not "get" OOP. Objects have one good use in my book: they make convenient namespaces. 90% of the time I see people using a million objects where they are not really needed, solely because OOP lets you waste time writing a skeleton when you otherwise have no clue what to do. But today I found a second redeeming quality to objects. Used sparingly, subclasses make great self documentation. I've been working on a project with some peculiar communications requirements. For performance testing, there might be a dozen network backends to try. The first backend will use IRC. (It is an old and crufty spec, but one of the only with multicast.) Here's some pseudocode: class Irc(object): def __init__(self): self.txq = Queue.Queue() self.rxq = Queue.Queue() self.irc = irclib.IRC() self.server = self.irc.server() self.irc.add_global_handler('pubmsg', self.handlePubMessage) self.connect() def connect(self): self.server.connect(**server_info) self.server.join(**channel_info) def tick(self): # batch send all txq messages self.irc.process_once() def handlePubMessage(self, connection, event): self.rxq.put_nowait(event.something()) def get(self): return self.rxq.get_nowait() def send(self, message): self.txq.put_nowait(message) ... and of course there are a **lot** of other event handlers to write (each parses an event into a message). And error handlers. These clutter up the object's namespace. The important parts are `connect()`, `tick()`, `get()` and `send()`. These methods will be common to every backend, but easy to get lost in the shuffle. How do you make this core interface clear? There will probably be 50 functions, handlers, and parsers in the `Irc` class. You'll have to look at the class for an hour to detangle them all. Adding clear docstrings would get half the way there, but that is not a good answer. Making all the IRC specific functions private would be the standard solution, but Python does not really have any concept of privacy. When it doubt, use more layers. We are going to make an otherwise useless object, but one designed to be very self documenting. It will only be a few lines long and contains stubs for the "public" functions every backend requires. The real object subclasses from public mock up. In this example, `Irc()` is still psuedocode but `Relay()` is taken straight from my actual source. class Relay(object): "Subclass this and flesh it out." def __init__(self): self.client_setup() self.client_connect() def client_setup(self, **kwargs): "Stuff that gets run once." pass def client_connect(self, **kwargs): "Will be called multiple times, if disconnected." pass def tick(self): "Called every frame from main loop." pass def get(self): "Retrieve one message, or None." pass def send(self, message): "Send a single message." pass class Irc(Relay): def client_setup(self): self.txq = Queue.Queue() self.rxq = Queue.Queue() self.irc = irclib.IRC() self.server = self.irc.server() self.irc.add_global_handler('pubmsg', self.handlePubMessage) def client_connect(self): self.server.connect(**server_info) self.server.join(**channel_info) def tick(self): # batch send all txq messages self.irc.process_once() def handlePubMessage(self, connection, event): self.rxq.put_nowait(event.something()) def get(self): return self.rxq.get_nowait() def send(self, message): self.txq.put_nowait(message) And that is one way to document through subclassing.
Preview