据我所知,装饰器是一个函数,它接受另一个函数作为参数,对它执行一些操作然后返回它。Python中的装饰器@staticmethod如何摆脱实例对象?
说到decorator @staticmethod,装饰器究竟做了什么来消除默认传递的实例对象?
据我所知,装饰器是一个函数,它接受另一个函数作为参数,对它执行一些操作然后返回它。Python中的装饰器@staticmethod如何摆脱实例对象?
说到decorator @staticmethod,装饰器究竟做了什么来消除默认传递的实例对象?
staticmethod
装饰工返回一个staticmethod
对象。该对象实现了descriptor protocol,与功能一样。
这是干什么的不是它将实例抛弃,而是将staticmethod.__get__
完全忽略绑定,只是返回未改变的函数对象。对于常规函数,function.__get__
将通过返回方法对象(然后跟踪实例和函数以在调用时组合它们)来绑定。
可以通过手动调用描述符协议重现此:
>>> 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>
通过经由Demo.__dict__
访问Demo
类的属性,我们绕过描述符协议通常由__getattribute__
方法执行。如您所见,对于常规方法,函数返回对象,但对于static
,则会找到staticmethod
对象。
调用.__get__(Demo())
来调用描述符协议,然后分别产生一个方法对象和未改变的函数对象。这正是直接访问同一个名字上的一个实例产生:
>>> Demo().regular
<bound method Demo.regular of <__main__.Demo object at 0x1084dde10>>
>>> Demo().static
<function Demo.static at 0x1085152f0>
需要注意的是相同的协议也是classmethod
对象传递type(instance)
而不是实例作为第一个参数的原因,也是为什么property
对象在访问时调用底层函数。
查看位于底部某处的Python实现:https://docs.python.org/3/howto/descriptor.html#static-methods-and-class-methods – vaultah