在 class 与实例上表现不同的函数
Function to behave differently on class vs on instance
我希望某个特定函数可以作为类方法调用,并且在调用实例时表现不同。
例如,如果我有一个 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
这里有一个有点老套的解决方案:
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
如果我们在class,执行staticmethod。如果我们在实例中,__getattribute__
首先被执行,所以我们可以 return 而不是 Thing.get_other_thing
而是其他一些函数(lambda
在我的例子中)
好问题!使用 描述符 .
可以轻松完成您要查找的内容
Descriptors 是 Python 实现 描述符协议 的对象,通常以 __get__()
.
它们的存在主要是为了在不同的 class 上设置为 class 属性。访问它们时,会调用它们的 __get__()
方法,并传入实例和所有者 class。
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
这很简单!
顺便说一句,你注意到我在 class 和实例函数上使用 __get__
了吗?你猜怎么着?函数也是描述符,这就是它们的工作方式!
>>> def func(self):
... pass
...
>>> func.__get__(object(), object)
<bound method func of <object object at 0x000000000046E100>>
访问函数属性时,它会被调用 __get__
,这就是您获得函数绑定的方式。
有关更多信息,我强烈建议阅读上面链接的 Python manual and the "How-To"。描述符是 Python 最强大的功能之一,甚至鲜为人知。
为什么不在实例化时设置函数?
或者为什么不在__init__
里面设置self.func = self._func
?
在实例化时设置函数有很多问题:
self.func = self._func
导致循环引用。该实例存储在 self._func
返回的函数对象中。另一方面,这在分配期间存储在实例上。最终结果是实例引用自身并将以更慢和更重的方式清理。
- 与您的 class 交互的其他代码可能会尝试直接从 class 中获取函数,并使用
__get__()
(通常预期的方法)来绑定它。他们将收到错误的功能。
- 不适用于
__slots__
。
- 虽然使用描述符您需要了解其机制,但在
__init__
上设置它并不干净,需要在 __init__
. 上设置多个函数
- 占用更多内存。您不是存储一个函数,而是为每个实例存储一个绑定函数。
- 不适用于 properties。
随着列表的不断增加,还有很多我没有添加。
我希望某个特定函数可以作为类方法调用,并且在调用实例时表现不同。
例如,如果我有一个 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
这里有一个有点老套的解决方案:
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
如果我们在class,执行staticmethod。如果我们在实例中,__getattribute__
首先被执行,所以我们可以 return 而不是 Thing.get_other_thing
而是其他一些函数(lambda
在我的例子中)
好问题!使用 描述符 .
可以轻松完成您要查找的内容Descriptors 是 Python 实现 描述符协议 的对象,通常以 __get__()
.
它们的存在主要是为了在不同的 class 上设置为 class 属性。访问它们时,会调用它们的 __get__()
方法,并传入实例和所有者 class。
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
这很简单!
顺便说一句,你注意到我在 class 和实例函数上使用 __get__
了吗?你猜怎么着?函数也是描述符,这就是它们的工作方式!
>>> def func(self):
... pass
...
>>> func.__get__(object(), object)
<bound method func of <object object at 0x000000000046E100>>
访问函数属性时,它会被调用 __get__
,这就是您获得函数绑定的方式。
有关更多信息,我强烈建议阅读上面链接的 Python manual and the "How-To"。描述符是 Python 最强大的功能之一,甚至鲜为人知。
为什么不在实例化时设置函数?
或者为什么不在__init__
里面设置self.func = self._func
?
在实例化时设置函数有很多问题:
self.func = self._func
导致循环引用。该实例存储在self._func
返回的函数对象中。另一方面,这在分配期间存储在实例上。最终结果是实例引用自身并将以更慢和更重的方式清理。- 与您的 class 交互的其他代码可能会尝试直接从 class 中获取函数,并使用
__get__()
(通常预期的方法)来绑定它。他们将收到错误的功能。 - 不适用于
__slots__
。 - 虽然使用描述符您需要了解其机制,但在
__init__
上设置它并不干净,需要在__init__
. 上设置多个函数
- 占用更多内存。您不是存储一个函数,而是为每个实例存储一个绑定函数。
- 不适用于 properties。
随着列表的不断增加,还有很多我没有添加。