Abusing Python classes as namespaces

June 22, 2011

Suppose, not entirely hypothetically, that you are dealing with binary structures and so have a bunch of functions to encode Python values to various different sorts of binary fields and decode those fields back to Python values. These functions clearly come in pairs.

There are various ways of organizing these functions; for example, you can just give them names like encode_uint16 and decode_uint16. One attractive way would be to group the pairs of functions together in namespaces, for example as uint16.encode and uint16.decode; this becomes even more useful if you add more per field type functions (for example, a validator function).

Unfortunately, Python does not have general namespace support. There is no convenient way to open up a new namespace and start defining things in it; all of the ways of creating namespaces come with various sorts of baggage. The closest Python comes to pure namespaces without side effects is modules, but you have to put them in separate files and I think that this gets ugly and hard to follow because the modules (and thus the files) are just too small.

(In theory one answer is to add some methods to your value types. However, even if you have modifiable classes for your value types, it may be inappropriate to add .encode and .decode methods to them because the same value type may have multiple different possible encodings. And if you're using basic Python values (ints, strings, etc), you don't even have modifiable classes to add methods to.)

The only real way to conveniently define multiple namespaces in a single file is to make them classes. But not conventional classes. Classes used purely as namespaces will never be instantiated; with no instances and no per-instance state, none of the 'methods' will actually ever use self and so there is no point in having them called with it. In short we want a class that has only staticmethod functions, because that makes them into regular plain old functions:

class uint16(object):
  @staticmethod
  def encode(val):
    return ...

  @staticmethod
  def decode(data):
    return ...

(This class deliberately breaks the usual Python naming convention for classes, because it's nothing like a normal class.)

In some cases it may be useful to have per-class data and some sort of class hierarchy in order to reuse code. That's the time for @classmethod.

PS: having tried this approach out in some of my code, I confess that I'm not sure I like it. The problem for me is an aesthetic one; I think I got the 'namespace' names wrong (I made them too class-like) and I'm not sure I like the @staticmethod's that are sprayed all over the place.

Written on 22 June 2011.
« It's long since time for languages to provide sensible network IO
A basic Namespace metaclass for Python »

Page tools: View Source, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Wed Jun 22 01:28:34 2011
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.