Sait
Sait

Reputation: 19805

Static method syntax confusion

This is how we make static functions in Python:

class A:
   @staticmethod
   def fun():
      print 'hello'

A.fun()

This works as expected and prints hello.

If it is a member function instead of a static one, we use self:

class A:
   def fun(self):
      print 'hello'

A().fun()

which also works as expected and prints hello.

My confusion is with the following case:

class A:
   def fun():
      print 'hello'

In the above case, there is no staticmethod, nor self. Python interpreter is okay with this definition. However, we cannot call it either of the above methods, namely:

A.fun()
A().fun()

both gives errors.

My question is: Is there any way that I can call this function? If not, why Python do not give me a syntax error in the first place?

Upvotes: 3

Views: 62

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1121306

Python doesn't give you a syntax error, because the binding of a method (which takes care of passing in self) is a runtime action.

Only when you look up a method on a class or instance, is a method being bound (because functions are descriptors they produce a method when looked up this way). This is done via the descriptor.__get__() method, which is called by the object.__getattribute__() method, which Python called when you tried to access the fun attribute on the A class or A() instance.

You can always 'unwrap' the bound method and reach for the un-wrapped function underneath to call it directly:

A.fun.__func__()

Incidentally, that's exactly what staticmethod does; it is there to 'intercept' the descriptor binding and return the raw function object instead of a bound method. In other words, staticmethod undoes the normal runtime method binding:

Demo:

>>> class A(object): pass
... 
>>> def fun(): print 'hello!'
... 
>>> fun.__get__(None, A)  # binding to a class
<unbound method A.fun>
>>> fun.__get__(None, A)()   # calling a bound function, fails as there is no first argument
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method fun() must be called with A instance as first argument (got nothing instead)
>>> fun.__get__(None, A).__func__  # access the wrapped function
<function fun at 0x100ba8378>
>>> staticmethod(fun).__get__(None, A)  # staticmethod object just returns the function
<function fun at 0x100ba8378>
>>> staticmethod(fun).__get__(None, A)()  # so calling it works
hello!

Upvotes: 9

Related Questions