我希望一个特定的函数可以作为类方法来调用,并且在实例上被调用时表现不同。
例如,如果我有一个class Thing
,我希望Thing.get_other_thing()
工作,但也希望thing = Thing(); thing.get_other_thing()
表现不同。
我认为在初始化时覆盖get_other_thing
方法应该可以工作(请参阅下文),但这似乎有点不客气。有更好的方法吗?
class Thing:
def __init__(self):
self.get_other_thing = self._get_other_thing_inst()
@classmethod
def get_other_thing(cls):
# do something...
def _get_other_thing_inst(self):
# do something else
答案 0 :(得分:6)
好问题!您可以使用描述符轻松完成搜索。
Descriptors 是实现 descriptor协议的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 manual和"How-To"链接。描述符是Python最强大的功能之一,甚至鲜为人知。
还是为什么不在self.func = self._func
中设置__init__
?
设置实例化功能会带来很多问题:
self.func = self._func
引起循环引用。实例存储在self._func
返回的函数对象中。另一方面,这是在分配期间存储在实例上的。最终结果是该实例引用了自己,并且将以慢得多,更沉重的方式进行清理。__get__()
(通常的预期方法)对其进行绑定。他们将收到错误的功能。__slots__
一起使用。__init__
上进行设置并不是那么干净,需要在__init__
上设置多个功能。随着列表的不断增加,我没有添加更多内容。
答案 1 :(得分:1)
这是一个有点棘手的解决方案:
class Thing(object):
@staticmethod
def get_other_thing():
return 1
def __getattribute__(self, name):
if name == 'get_other_thing':
return lambda: 2
return super(Thing, self).__getattribute__(name)
print Thing.get_other_thing() # 1
print Thing().get_other_thing() # 2
如果我们在上课,则将执行staticmethod。如果我们在实例上,首先要执行__getattribute__
,所以我们不能返回Thing.get_other_thing
,而是返回其他函数(在我的情况下,返回lambda
)