Could you explain why the following code snippet doesn't work?
class A:
@staticmethod
def f():
print('A.f')
dict = {'f': f}
def callMe(g):
g()
callMe(A.dict['f'])
It yields
TypeError: 'staticmethod' object is not callable
Interesingly, changing it to
class A:
@staticmethod
def f():
print('A.f')
dict = {'f': f}
def callMe(g):
g()
callMe(A.f)
or to
class A:
@staticmethod
def f():
print('A.f')
dict = {'f': lambda: A.f()}
def callMe(g):
g()
callMe(A.dict['f'])
gives the expected result
A.f
As far as I see the behaviour is the same in Python 2 and 3.
2 Answers 2
The f object inside A is a descriptor, not the static method itself -- it returns the staticmethod when called with an instance of A; read the link, and look up the "descriptor protocol" for more info on how this works. The method itself is stored as the __func__ attribute of the descriptor.
You can see this for yourself:
>>> A.f
<function A.f at 0x7fa8acc7ca60>
>>> A.__dict__['f']
<staticmethod object at 0x7fa8acc990b8>
>>> A.__dict__['f'].__func__ # The stored method
<function A.f at 0x7fa8acc7ca60>
>>> A.__dict__['f'].__get__(A) # This is (kinda) what happens when you run A.f
<function A.f at 0x7fa8acc7ca60>
Also note that you can use A.__dict__ to access the f descriptor object, you don't need to make your own dictionary to store it.
Comments
The staticmethod object is a descriptor, and you need to access it as an attribute (of the class) for the descriptor mechanism to take effect. The staticmethod object itself is not callable, but the result of its __get__ is callable. See also this Python bug discussion.