Python Static Utility Class – Best Way to Create and Is Using Metaclasses a Code Smell?

code smellpython

Ok so I need to create a bunch of utility classes in python. Normally I would just use a simple module for this but I need to be able to inherit in order to share common code between them. The common code needs to reference the state of the module using it so simple imports wouldn't work well. I don't like singletons, and classes that use the classmethod decorator do not have proper support for python properties.

One pattern I see used a lot is creating an internal python class prefixed with an underscore and creating a single instance which is then explicitly imported or set as the module itself. This is also used by fabric to create a common environment object (fabric.api.env).

I've realized another way to accomplish this would be with metaclasses. For example:

#util.py
class MetaFooBase(type):
    @property
    def file_path(cls):
        raise NotImplementedError

    def inherited_method(cls):
        print cls.file_path


#foo.py
from util import *
import env

class MetaFoo(MetaFooBase):
    @property
    def file_path(cls):
        return env.base_path + "relative/path"

    def another_class_method(cls):
        pass

class Foo(object): __metaclass__ = MetaFoo


#client.py
from foo import Foo

file_path = Foo.file_path

I like this approach better than the first pattern for a few reasons:

First, instantiating Foo would be meaningless as it has no attributes or methods, which insures this class acts like a true single interface utility, unlike the first pattern which relies on the underscore convention to dissuade client code from creating more instances of the internal class.

Second, sub-classing MetaFoo in a different module wouldn't be as awkward because I wouldn't be importing a class with an underscore which is inherently going against its private naming convention.

Third, this seems to be the closest approximation to a static class that exists in python, as all the meta code applies only to the class and not to its instances. This is shown by the common convention of using cls instead of self in the class methods. As well, the base class inherits from type instead of object which would prevent users from trying to use it as a base for other non-static classes. It's implementation as a static class is also apparent when using it by the naming convention Foo, as opposed to foo, which denotes a static class method is being used.

As much as I think this is a good fit, I feel that others might feel its not pythonic because its not a sanctioned use for metaclasses which should be avoided 99% of the time. I also find most python devs tend to shy away from metaclasses which might affect code reuse/maintainability. Is this code considered code smell in the python community? I ask because I'm creating a pypi package, and would like to do everything I can to increase adoption.

Best Answer

I think it is a bad idea.

Its a very odd use of meta classes which will contribute to confusion of anyone trying to follow your code. In order to make it worth using this technique, you need the advantages to outweigh that confusion.

As for your reasons:

  1. Creating an accesible Foo class that can be instantiated, but doesn't actually work like a typical object is much more prone to misuse than an internal class that you know you aren't supposed to call.
  2. Don't name the base class with an underscore. If its intended to be inherited by other modules, it shouldn't be named that way.
  3. There already is a method to implement static classes in python, staticmethod or classmethod. As noted, its not hard to implement a staticproperty

In general, there is a theme in your approach of trying to prevent client code from doing the wrong thing. That's not a pythonic attitude. The pythonic approach is to trust your client code. If they want to do something crazy, let them. Don't try to prevent client from instantiating your internal object, there may well be a good reason to do that.

I'm a bit of a purist and think that you shouldn't be storing state like this. So the very fact that you are asking the question means you're already doing it wrong. If you have state, I think it should be in an object. I think storing any sort of state at the module level should be avoided. I think its only a good idea to implement something like this if you have no changing state.

To close off, I'd like to plug the Code Review Stack Exchange, where I'm a moderator. If you post your code there you can get suggestions on how to make it better. I think you may get some helpful suggestions for how to restructure your code to avoid this question from even coming up.

Related Topic