好问题!使用描述符可以轻松完成您所寻求的工作。
描述符是实现描述符协议的 Python 对象,通常以__get__()
.
它们的存在主要是为了设置为不同类的类属性。访问它们时,将__get__()
调用它们的方法,并传入实例和所有者类。
class DifferentFunc:
"""Deploys a different function accroding to attribute access
I am a descriptor.
"""
def __init__(self, clsfunc, instfunc):
# Set our functions
self.clsfunc = clsfunc
self.instfunc = instfunc
def __get__(self, inst, owner):
# Accessed from class
if inst is None:
return self.clsfunc.__get__(None, owner)
# Accessed from instance
return self.instfunc.__get__(inst, owner)
class Test:
@classmethod
def _get_other_thing(cls):
print("Accessed through class")
def _get_other_thing_inst(inst):
print("Accessed through instance")
get_other_thing = DifferentFunc(_get_other_thing,
_get_other_thing_inst)
现在的结果:
>>> Test.get_other_thing()
Accessed through class
>>> Test().get_other_thing()
Accessed through instance
那很简单!
顺便说一句,你注意到我__get__
在类和实例函数上使用了吗?你猜怎么着?函数也是描述符,这就是它们的工作方式!
>>> def func(self):
... pass
...
>>> func.__get__(object(), object)
<bound method func of <object object at 0x000000000046E100>>
在访问函数属性时,它会__get__
被调用,这就是你获得函数绑定的方式。
有关更多信息,我强烈建议阅读Python 手册和上面链接的“操作方法” 。描述符是 Python 最强大的功能之一,甚至鲜为人知。
为什么不设置实例化功能?
或者为什么不设置self.func = self._func
在里面__init__
?
在实例化时设置函数会带来很多问题:
self.func = self._func
导致循环引用。该实例存储在由返回的函数对象中self._func
。另一方面,这在分配期间存储在实例上。最终结果是实例引用自身,并且将以更慢和更重的方式进行清理。
- 与您的类交互的其他代码可能会尝试直接从类中取出函数,并使用
__get__()
通常的预期方法来绑定它。他们将收到错误的功能。
- 不会与
__slots__
.
- 尽管使用描述符您需要了解机制,但设置它
__init__
并不那么干净,需要在__init__
.
- 占用更多内存。不是存储一个函数,而是为每个实例存储一个绑定函数。
- 不适用于属性。
随着列表的继续,还有很多我没有添加。