As far as I have understood, a decorator is a function that takes another function as a parameter, performs some operation on it and then returns it.
Talking about the decorator @staticmethod, what exactly does that decorator do to eliminate the instance object that is being passed by default ?
The staticmethod decorator returns a staticmethod object. This object implements the descriptor protocol, same as functions do.
What this does is not that it gets rid of the instance, instead the staticmethod.__get__ ignores binding altogether and just returns the unaltered function object. For regular functions, function.__get__ would instead bind by returning a method object (which then tracks the instance and the function to combine them when called).
You can reproduce this by manually invoking the descriptor protocol:
>>> class Demo:
... def regular(self):
... pass
... @staticmethod
... def static():
... pass
...
>>> Demo.__dict__['regular'] # bypass __getattribute__
<function Demo.regular at 0x108515268>
>>> Demo.__dict__['static'] # bypass __getattribute__
<staticmethod object at 0x1084d4f60>
>>> Demo.__dict__['regular'].__get__(Demo()) # descriptor protocol, pass in an instance
<bound method Demo.regular of <__main__.Demo object at 0x1084e2668>>
>>> Demo.__dict__['static'].__get__(Demo()) # descriptor protocol, pass in an instance
<function Demo.static at 0x1085152f0>
By accessing the attributes of the Demo class through Demo.__dict__, we bypass the descriptor protocol normally enforced by the __getattribute__ method. As you can see, for a regular method a function object is returned, but for static a staticmethod object is found instead.
Calling .__get__(Demo()) on either to invoke the descriptor protocol then produces a method object, and the un-altered function object, respectively. This is exactly what direct access to the same names on an instance produces:
>>> Demo().regular
<bound method Demo.regular of <__main__.Demo object at 0x1084dde10>>
>>> Demo().static
<function Demo.static at 0x1085152f0>
Note that the same protocol is also the reason that classmethod objects are passed type(instance) instead of the instance as a first argument, and also why property objects call the underlying function on access.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With