August 23rd, 2007


I discuss Python class methods, to the delight of all


with your host, Amar

Python has the notion of class methods. I haven't quite wrapped my head around this concept.

In Python, everything's a namespace. Classes are namespaces whose functions all have an implicit first parameter, 'self.' 'self' represents an anonymous namespace, i.e. an object. (Objects are namespaces too!) A new anonymous namespace is created when an object is constructed, and it's passed as a hidden first argument whenever the object's methods are called.
class Foo:                       # defines namespace Foo
   def set_name(self, name):     # defines instance method set_name(name), implicit first argument = name           # have to use 'self' when changing object state

   def get_name(self):

myFoo = Foo()                    # creates new anonymous namespace, #234121 or whatever                               
myFoo.set_name("Mary")           # calls Foo.set_name(#234121, "Mary")
myFoo.get_name()                 # returns

That covers instance methods. But Python developers also wanted something equivalent to static class methods in C++. So they introduced the notion of "decorators." Decorators are little directives that tell the interpreter to add or not add implicit parameters. The syntax is similar to compiler directives in C++:
class Foo():
    doSomething(self, arg):            # instance method   

    doSomethingElse(arg):              # decorated with static, no implicit 'self' parameter

myFoo = Foo()
myFoo.doSomething('22skidoo')          # ok
myFoo.doSomething('hello', '22skidoo') # error = doSomething only takes one explicit arg
myFoo.doSomethingElse('22skidoo')      # ok, static method can be invoked via instance, no implicit 'self' parameter
Foo.doSomethingElse('22skidoo')        # ok, same as above but invoked via class

Aside from the whole "callable via object" thing, the @staticmethod decorator is pretty similar to the "static" declaration in C++. But Python also has @classmethod, which (though confusingly named) does not refer to instance methods of a class.

Class methods have an implicit first argument, like 'self'. But this first argument is a reference to the namespace of the class itself, not some instance of the class. You can use this reference to access everything in the class namespace.

What's the point? After all, static methods of Foo can already access everything in the Foo namespace. Why bother passing it in as a parameter? The answer (I think) is that unlike static method, class methods can mix in subclass functionality with base class functionality. e.g.
class Foo:
   modifyAmount = 1                # static variable, Foo.modifyAmount
     return var + modifyAmount     # always uses Foo.modifyAmount

   modifyClass(cls, var):         
     return var + cls.modifyAmount # accesses modifyAmount via implicit cls argument

class Bar(Foo):
   modifyAmount = 100              # static variable, Bar.modifyAmount

myFoo = Foo()
myBar = Bar()
myFoo.modifyStatic(4)              # returns 5
myBar.modifyStatic(4)              # returns 5,  even though Bar.modifyAmount is 100
myFoo.modifyClass(4)               # returns 5,  same as myFoo.modifyStatic
myBar.modifyClass(4)               # returns 104, because implicit cls argument was used when getting modifyAmount
This looks like one of the classic software design patterns -- Mixin or Strategy or what have you. Basically the base class can define some functionality that requires subclasses to 'fill in' particular details. Like a base database class that knows about general cursors and querying and stuff, but lets particular table subclasses fill in the details of their specific queries/data.

In C++ you could accomplish the same thing by defining a non-virtual function that uses virtual functions... right? Is that all @classmethod accomplishes? Like I said, I haven't quite figured it out yet. Let's just say my interest is not entirely academic.

previously on Geek Korner