The Static Method Thing

Phillip J. Eby has a recent weblog entry, Python is not Java, wherein he points out a few aspects of Python that are notably different from Java but that are similar enough that Java coders working in Python mistake them for their Java counterparts.

He touches on a few of the characteristics that led me to make Python my general purpose language of choice, a title that had belonged to Java as recently as a year ago. I thought it might be useful to explain these characteristics without assuming the reader has a whole lot of Python experience but that they do have significant Java experience. This would have helped me immensely in determining whether Python was right for me much sooner and I hope it can be of use to someone else.

I’m planning on covering each of the items Phillip points out in his article over the next month and if that works out, I may extend the series to a few other things that may be useful.

This is not a Python is better than Java thing. Instead of bashing aspects of Java’s language and library that are obviously valued by the Java community, or insulting the intelligence of Java coders, or using any number of other techniques you might find in Every Language War Ever, Phillip is simply asking Java programmers who may be dabbling in Python to take a closer look at some of the features that make Python unique and attractive instead of attempting to force-fit concepts from Java. If you base your expectations of Python on Java concepts, you are likely going to have a bad experience with Python.

Continue on for the first part of the series, which talks about some of the differences between Python class methods / class variables and Java static methods / static variables.

Python Class Methods are not Java Static Methods

I’ll start from the top with the comment on static variables and methods in Java and why the equivalent Python code looks a bit different:

A static method in Java does not translate to a Python classmethod. Oh sure, it results in more or less the same effect, but the goal of a classmethod is actually to do something that’s usually not even possible in Java (like inheriting a non-default constructor).

We’ll get into the inheriting a non-default constructor bit in a second. For now, let’s take a look at a static variable and method in Java:

public class X {
  public static String message = "Hello";
  public static void sayHello() {
    System.out.println(X.message);
  }
}

Calling this method from another class looks like this:

import X
public class Main {
  public static void main(String[] args) {
    X.sayHello();
  }
}

Now, if you’re teaching someone to program and using Java to illustrate, this situation kind of sucks. You’ve introduced classes, the static modifier, and access modifiers - all before you can even start to talk about the basic concept of a function (led alone a method) or writing output to the screen. (Note: this makes Java only mildly less shitty than C++ for teaching programming because at least you don’t have to deal with pointers and operator overloading: cout << "Hello".)

Whether Java’s constraint of requiring everything to be written within a class was a good idea is debatable (and it has been debated to death). On the one hand, it forces programmers to think about programming using OOP concepts, which generally helps ensure that code is somewhat reusable (so the theory goes). On the other hand, it forces programmers to think about programming using OOP concepts, even when they may be overkill. This leads to code like the example above that has a lot of extra scenery to distract you from the intent.

The idiomatic translation of a Java static method is usually a module-level function, not a classmethod or staticmethod. (And static final fields should translate to module-level constants.)

Here’s the idiomatic translation to Python of the Java example above. The following is in a module file named X.py:

message = "Hello"
def say_hello():
    print message

And calling the function from another module (in Main.py):

import X
X.say_hello()

Now let’s look at an example of what not to do in Python:

class X:
    message = "Hello"
    def say_hello(cls):
        print X.message
    say_hello = classmethod(say_hello)

Calling the above from another module looks like this:

import X
X.X.say_hello()

Here’s why: in Python, each module is itself an object without having to define an explicit class. A single module in Python maps to a single .py file on disk. Modules may contain functions, attributes (variables), multiple class definitions, etc. There is no equivalent of the Python module in Java - each .java file must have a single top-level class that matches the filename. Imports in Java work at the class level; imports in Python work at the module level.

This may just confuse things further but it may help for the Java inclined to think of each Python module as acting like a purely static Java class. Functions defined at the top level of a module are static methods on the class. Variables defined at the top level of a module are static members. Classes defined at the top level of a module act like public static inner classes. In other words, the idiomatic Python example maps exactly to the Java example without having to write an explicit class at all. The example of what not to do in Python would look like this if you ported it directly to Java:

public class X {
  public static class X {
    public static String message = "Hello";
    public void sayHello() {
        System.out.println(X.X.message);
    }
  };
}

It should now be obvious why the second form is incorrect in Python, it’s incorrect in Java!

Class Method Inheritance

So why have a Java static method like construct in Python at all? Phillip begins to answer that question in his post:

the goal of a classmethod is actually to do something that’s usually not even possible in Java (like inheriting a non-default constructor).

In a Python classmethod, the class object that the method is invoked on is passed as the first parameter to the method. This can be used for a variety of weird and arcane things but the most common use is for factory-style constructors.

Like static methods in Java, Python classmethods are inherited by subclasses. Unlike Java, it is possible for subclasses to override classmethods. Python also passes the class object that a classmethod is called on to the method as the first parameter. This gives superclasses access to the subclass’ methods (such as the constructor).

Here’s an example that provides a caching mechanism for new classes:

class Cacheable:
    _cache = {}
    def create_cached(cls, value):
        if not cls._cache.has_key(value):
            print 'cache miss'
            rslt = cls(value)
            cls._cache[value] = rslt
        else:
            print 'cache hit'
            rslt = cls._cache[value]
        return rslt
    create_cached = classmethod(create_cached) 

class X(Cacheable):
    def __init__(self, value):
        self.value = value

x = X.create_cached('test')  # X instance created
x = X.create_cached('test2') # X instance created
x = X.create_cached('test')  # X instance taken from cache

When we call X.create_cached(), the method is called on the Cacheable class but the cls argument is set to the X class object. This means that many classes can subclass Cacheable and inherit the class methods it defines (including __new__, which is something we won’t get into).

This technique is actually used very rarely in Python as there are usually simpler ways of accomplishing the same thing, and simplicity is highly valued in Python.

I hope this helped illuminate the difference between Python class methods/variables and Java static methods/variables. Remember, the point isn’t to convince you that Python classmethods are somehow cooler than Java static methods or vice versa, just that the two concepts are not equivalent.