我有一个数据存储延迟加载的描述符,如果数据存储不可用,则返回默认值。描述符工作正常,除了我希望默认值是提供的类类型的实例的情况,该类型是与定义描述符相同的类类型(树层次结构所需)。理想情况下我想做
from weakref import WeakKeyDictionary
class Descriptor(object):
def __init__(self, classType=None):
self.classType = classType
self.values = WeakKeyDictionary()
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner):
print("name:", self.name)
if instance not in self.values:
self.values[instance] = self.classType()
return self.values[instance]
def __set__(self, instance, value):
self.values[instance] = value
class Item1(object):
pass
class Item2(object):
parent1 = Descriptor(Item1)
parent2 = Descriptor(Item2)
item2 = Item2()
print(item2.parent1)
print(item2.parent2)
但很明显,parent2的描述符不能传递给它定义的类。所以另一种方法是在定义类后指定parent2:
class Item2(object):
parent1 = Descriptor(Item1)
Item2.parent2 = Descriptor(Item2)
但是,在这种情况下,在创建构造函数时似乎没有调用__set_name__方法,因为给出了以下错误:
name: parent1
<__main__.Item1 object at 0x021F4890>
Traceback (most recent call last):
File "..\setNameTest.py", line 28, in <module>
print(item2.parent2)
File "..\setNameTest.py", line 10, in __get__
print("name:", self.name)
AttributeError: 'Descriptor' object has no attribute 'name'
在类中创建Descriptor之后,似乎只是将itemClass值分配给parent2,但在整个代码库中使用它似乎很笨拙:
class Item2(object):
parent1 = Descriptor(Item1)
parent2 = Descriptor()
Item2.__dict__['parent2'].classType = Item2
有更干净的方法吗?
编辑09Mar2017: 根据{{3}},如果实例为无,则从Descriptor返回self .__ get__可以清除此方法,即
def __get__(self, instance, owner):
if instance is None:
return self
print("name:", self.name)
if instance not in self.values:
self.values[instance] = self.classType()
return self.values[instance]
现在可以通过
在类定义之外分配classTypeItem2.parent2.classType = Item2
答案 0 :(得分:0)
因此,当您需要在类级别范围内访问类本身时,必须使用元类。但是,我不熟悉新的__set_name__
dunder方法,而且我无法使用元类工作。然而,这是一种替代方式 - 旧方式 - 。首先,您必须将name
传递给Descriptor
__init__
:
In [10]: from weakref import WeakKeyDictionary
...:
...: class Descriptor(object):
...: def __init__(self, name, classType=None):
...: self.classType = classType
...: self.values = WeakKeyDictionary()
...: self.name = name
...: def __get__(self, instance, owner):
...: print("name:", self.name)
...: if instance not in self.values:
...: self.values[instance] = self.classType()
...: return self.values[instance]
...: def __set__(self, instance, value):
...: self.values[instance] = value
...:
...:
...: class Item1(object):
...: pass
...:
现在,定义您的元类。这可能是更好的封装,但它可以解决这个问题。请注意,我正在将name
传递给Descriptor
:
In [11]: class ItemMeta(type):
...: def __init__(cls, name, bases, dct):
...: cls.parent1 = Descriptor('parent1', Item1)
...: cls.parent2 = Descriptor('parent2', cls)
...:
...:
最后,使用Python3语法,我们使用元类创建Item2
:
In [12]: class Item2(object, metaclass=ItemMeta):
...: pass
...:
现在,它应该有效:
In [13]: x = Item2()
In [14]: x.parent1
name: parent1
Out[14]: <__main__.Item1 at 0x1104db240>
In [15]: x.parent2
name: parent2
Out[15]: <__main__.Item2 at 0x1104dbc50>