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 self.name = name # have to use 'self' when changing object state def get_name(self): return self.name myFoo = Foo() # creates new anonymous namespace, #234121 or whatever myFoo.set_name("Mary") # calls Foo.set_name(#234121, "Mary") myFoo.get_name() # returns #234121.name
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 ... @staticmethod 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 @staticmethod modifyStatic(var) return var + modifyAmount # always uses Foo.modifyAmount @classmethod 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 modifyAmountThis 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.