Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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.

share|improve this question
3  
Why do you want a "utility class" to begin with? What's wrong with module-level functions and constants? I feel it is not idiomatic because it avoids a perfectly simple solution and adds a lot of complexity just to introduce a concept which reeks of another language, not because it uses metaclasses unconventionally (I do that myself). –  delnan May 17 '13 at 18:05
    
I think 99% of the time I agree with you on this, and I don't think this is a pattern I'd use often. I'm creating data file utility classes and I have the common code in a common separate module (load, save, etc). Load and save reference a class specific file path calculated at runtime and save/load the data in a class variable. I'm also using method decorators that automatically handles locking the file, loading it, calling the method, saving it, and unlocking it. This is very hard to do properly without classes. So its a bit motivated by convenience. –  rsimp May 17 '13 at 18:27
    
"classes that use the classmethod decorator do not have proper support for python properties": you can easily find a classproperty decorator on the web, or write one yourself. I use one very frequently. –  shx2 May 18 '13 at 5:34
    
Yes this works well if you are only setting the getter for the property. It breaks down when you try to set the setter as shown here: stackoverflow.com/questions/128573/… . The best way to implement both the setter and getter for a class property is through the use of metaclasses which is actually what inspired this design. If you're going to go through the trouble to make a metaclass, you might as well put all of the class specific information inside of it. –  rsimp May 18 '13 at 6:23
    
3 comments above you said you wrote code. Can we have a look at it? I think this would help understand. –  User May 30 '13 at 13:43
add comment

2 Answers

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 your 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 http://codereview.stackexchange.com, 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.

share|improve this answer
add comment

Metaclasses are a powerful tool. Most of the time they are not needed, but it looks like you have solid reasons for doing so. I do not see your use of metaclasses, or lack thereof, affecting your package's adoption on PyPI.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.