Python - why can I call a class method with an instance?

Steve Ives picture Steve Ives · May 12, 2015 · Viewed 12.5k times · Source

New to Python and having done some reading, I'm making some methods in my custom class class methods rather than instance methods.

So I tested my code but I hadn't changed some of the method calls to call the method in the class rather than the instance, but they still worked:

class myClass:
   @classmethod:
   def foo(cls):
      print 'Class method foo called with %s.'%(cls)

   def bar(self):
      print 'Instance method bar called with %s.'%(self)

myClass.foo()
thing = myClass()
thing.foo()
thing.bar()

This produces:

class method foo called with __main__.myClass.
class method foo called with __main__.myClass.
instance method bar called with <__main__.myClass instance at 0x389ba4>.

So what I'm wondering is why I can call a class method (foo) on an instance (thing.foo), (although it's the class that gets passed to the method)? It kind of makes sense, as 'thing' is a 'myClass', but I was expecting Python to give an error saying something along the lines of 'foo is a class method and can't be called on an instance'.

Is this just an expected consequence of inheritance with the 'thing' object inheriting the foo method from its superclass?

If I try to call the instance method via the class:

myClass.bar()

then I get:

TypeError: unbound method bar() must be called with myClass instance...

which makes perfect sense.

Answer

John picture John · May 12, 2015

You can call it on an instance because @classmethod is a decorator (it takes a function as an argument and returns a new function).

Here is some relavent information from the Python documentation

It can be called either on the class (such as C.f()) or on an instance (such as C().f()). The instance is ignored except for its class. If a class method is called for a derived class, the derived class object is passed as the implied first argument.

There's also quite a good SO discussion on @classmethod here.