Now I have a reason to use staticmethod

The python builtin staticmethod has been one of those language features that I understood, but couldn’t figure out why I would ever use it. When I did my PyOhio talk on decorators, I asked if anyone in the room could explain why to use it. People came up with these ideas:

  • Put associated functions inside the relevant class, so we don’t pollute the module namespace
  • Make java programmers feel less homesick

Both of these are valid, I guess, but in my mind, it just confirmed that I would never use staticmethod.

Then I watched this neat video. You don’t have to go watch that video before you read the next section. I just wanted to point to where I picked up this trick.

Remember that any function bound to a class gets called with an extra parameter inserted at the beginning. That parameter is a reference to the instance of the class. So, you can’t do this:

>>> def f(a, b):
... return a - b
...
>>> class C(object):
... pass
...
>>> C.f = f
>>> c = C()
>>> c.f(3, 1)
------------------------------------------------------------
Traceback (most recent call last):
File "", line 1, in
TypeError: f() takes exactly 2 arguments (3 given)

The call to f blew up because f only takes two parameters, but it got three parameters instead because python automatically adds on the self parameter at the beginning. So f really got called like this: f(self, 3, 1)

Now the reason for staticmethod becomes obvious. If I want to allow instances of my class C to call function f, I have to make f a staticmethod on C, so that the python plumbing won’t insert that extra first argument at the beginning.

So, I’ll overwrite the first C.f method with a static method, and then call c.f again:

>>> C.f = staticmethod(f)
>>> c.f(3, 1) # This is the same already-instantiated c from earlier.
2

As a side effect of watching that video, I think about dependency injection (DI) differently now. In the video, Thomas Woulters says he uses staticmethod for dependency injection. This kind of DI is a different approach than what I’ve seen before. Most everybody that talks about DI emphasizes passing in lots and lots of crap into the __init__ method or in any subsequent methods, so every component can be mocked out.

But it makes just as much sense to graft on dependencies to the class outside of the __init__ method too, since the language supports that. The end goal is still reached. Code can still tweak the dependencies and provide alternative objects, and at the same time, I don’t end up with ridiculously long function signatures.

9 thoughts on “Now I have a reason to use staticmethod

  1. I use staticmethod to indicate that a method has no side effects (you can't modify self if it doesn't even get passed in). Using it to replace methods is interesting, but I always find that such things are non-obvious when I go back to the code after six months. I can think of a few situations in testing where it would've been quite useful, though.

  2. If you've ever used dict.fromkeys you are using a staticmethod. (Although it is implemented on the C side, so a little different). Hopefully this shows an example of another place staticmethod is great; alternate constructors.

    Larger libraries don't always have the luxury of knowing the module for every class that gets passed around. Using the static methods allows the entire api to travel around with the class description. This is a huge convenience. It is definitely for more than “make java people comfortable.”

  3. Hi Pete, Thanks for the comment.

    Could dict.fromkeys also be implemented as a classmethod? I make alternate constructors all the time, but I make them classmethods, so that I still have a reference to the class that I want to make instances out of.

    When I subclass a dict, then call fromkeys on my subclass, it returns an instance of my subclass. I don't see how that would work with a staticmethod, since it doesn't seem to have any association with the class.

    I'm not sure I understand what you mean about how large libraries don't know the module of every class. Is it the case where module B imports a class from module A, and then another module C imports that class from module B? In that case, I can definitely see the merit of bundling all related code together in the class.

    I'm not against staticmethods. I just never could see myself using them.

    Matt

  4. Hey Gary,

    I like the idea of using staticmethod as an annotation to make it clear that the method doesn't alter the class. It could still have side effects though; it could mangle the parameters passed in, right?

    Matt

  5. Yep, it could still mangle the parameters. I think I do that in a few places. The main benefit for me is that I can glance at a class and say “Ok, I know that all actual changes to this object are isolated to these two non-static methods.”

  6. I staticmethod shows that the method has no side effects (you can change, even if it is not accepted). Using the substitution method is interesting, but I always find that these things are not obvious, when I go back to the code in six months. I can imagine some situations in the test phase, where it would be very useful, though.
    Kamagra
    Kamagra

Comments are closed.