Python:缓存描述符的值
我想澄清一些关于Python描述符的事情。我想用一些复杂的set/get机制向类中添加一个属性,并将这些计算值缓存在描述符对象中。简化的示例如下所示:Python:缓存描述符的值,python,descriptor,Python,Descriptor,我想澄清一些关于Python描述符的事情。我想用一些复杂的set/get机制向类中添加一个属性,并将这些计算值缓存在描述符对象中。简化的示例如下所示: class Pro(object): """My descriptor class""" def __init__(self): self.value = None def __get__(self, instance, owner): return self.value de
class Pro(object):
"""My descriptor class"""
def __init__(self):
self.value = None
def __get__(self, instance, owner):
return self.value
def __set__(self, instance, value):
self.value = value
class Something(object):
"""My simple class"""
pro = Pro()
a = Something()
a.pro = 1
b = Something()
b.pro = 2
print(a.pro, b.pro) # At first, I've expected them to be 1 and 2
我想,
pro
属性应该是pro
的唯一实例,对于某物的每个实例,显然我错了。看起来我应该使用类似于instance.\u value
的东西,而不是self.value
在\u set\u
和\u get\u
中,但是我真的希望把所有东西都隐藏在Pro
类中。这可能吗?谢谢 代码的问题在于,您正在设置Pro实例的属性,该属性将由某物的所有实例共享。要解决此问题,应在某物的单个实例上设置一个属性,一种方法是使用元类:
class Meta(type):
def __new__(cls, name, bases, dct):
for k, v in dct.items():
if isinstance(v, Pro):
# add an _ in front of the name
v.name = '_' + k
return super(Meta, cls).__new__(cls, name, bases, dct)
class Pro(object):
def __get__(self, ins, typ):
return getattr(ins, self.name)
def __set__(self, ins, val):
setattr(ins, self.name, val)
class Something(object):
"""My simple class"""
__metaclass__ = Meta
pro = Pro()
a = Something()
a.pro = 1
b = Something()
b.pro = 2
演示:
>>> a.pro, b.pro
(1, 2)
>>> a.__dict__
{'_pro': 1}
>>> b.__dict__
{'_pro': 2}
>>> a.pro = 100
>>> a.__dict__
{'_pro': 100}
1 2
[(<__main__.Something object at 0x7fb80d0d5310>, 1), (<__main__.Something object at 0x7fb80d0d5350>, 2)]
[(<__main__.Something object at 0x7fb80d0d5350>, 2)]
所以在某些东西中没有办法隐藏属性
实例,对吗
不,有。您可以在Pro
的实例中存储字典,该字典存储与某物的每个实例相关的所有值。例如,如果某物的实例是可散列的,那么您可以使用。WeakKeyDictionary
将确保一旦某个某物的实例没有剩余引用,它将立即被垃圾收集,这是正常的dict
无法做到的:
from weakref import WeakKeyDictionary
class Pro(object):
def __init__(self):
self.instances = WeakKeyDictionary()
def __get__(self, ins, typ):
return self.instances[ins]
def __set__(self, ins, val):
self.instances[ins] = val
p = Pro()
class Something(object):
"""My simple class"""
pro = p
a = Something()
a.pro = 1
b = Something()
b.pro = 2
print a.pro, b.pro
print p.instances.items()
del a
print p.instances.items()
输出:
>>> a.pro, b.pro
(1, 2)
>>> a.__dict__
{'_pro': 1}
>>> b.__dict__
{'_pro': 2}
>>> a.pro = 100
>>> a.__dict__
{'_pro': 100}
1 2
[(<__main__.Something object at 0x7fb80d0d5310>, 1), (<__main__.Something object at 0x7fb80d0d5350>, 2)]
[(<__main__.Something object at 0x7fb80d0d5350>, 2)]
12
[(, 1), (, 2)]
[(, 2)]
你看了吗?@Lemming,看起来很整洁,谢谢,但我只希望用标准库来解决这个问题:)很公平。顺便说一句,与大多数python包一样,这一个是开源的。非常小,非线程版本不需要任何额外的包。源代码很有趣,谢谢,直到现在才看到它。所以在Something
实例中没有办法隐藏属性,对吗?如果要“缓存”实例的值,该值必须与实例关联。Python属性基本上是通过使用对象的dict字典来实现的。您可以通过在描述中使用实例作为键的字典来逆转它,但基本问题仍然是您需要实例到值的映射,反之亦然versa@AntonMelnikov当然这也是可能的,请参阅更新。@AshwiniChaudhary好的,我想我现在明白了。谢谢你的解释。