[英]why does global in a class behave differently when the class is within a function?
[英]Function to behave differently on class vs on instance
我希望一个特定的函数可以作为类方法调用,并且当它在一个实例上调用时表现不同。
例如,如果我有一个class Thing
,我希望Thing.get_other_thing()
能够工作,而且还有thing = Thing(); thing.get_other_thing()
thing = Thing(); thing.get_other_thing()
表现不同。
我认为在初始化时覆盖get_other_thing
方法应该可以工作(见下文),但这看起来有点hacky。 有没有更好的办法?
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
好问题! 您使用描述符可以轻松完成您所寻求的内容。
描述符是实现描述符协议的 Python对象,通常以__get__()
开头。
它们主要存在于不同类中的类属性。 在访问它们时,将__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最强大的功能之一,几乎不为人所知。
或者为什么不在__init__
设置self.func = self._func
?
在实例化时设置函数会带来很多问题:
self.func = self._func
导致循环引用。 该实例存储在self._func
返回的函数对象中。 另一方面,这在分配期间存储在实例上。 最终结果是实例引用自身并以更慢和更重的方式清理。 __get__()
(这是通常的预期方法)来绑定它。 他们将收到错误的功能。 __slots__
。 __init__
上设置它并不是很干净,需要在__init__
上设置多个函数。 随着列表的不断发展,我还没有添加更多内容。
这是一个有点hacky解决方案:
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
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.