Python中的描述符类设计(带继承)
我试图设计一个描述符类,我可以通过另一个类使用它,这个类是一个类的子类,而这个类是一个类的子类Python中的描述符类设计(带继承),python,class,inheritance,descriptor,Python,Class,Inheritance,Descriptor,我试图设计一个描述符类,我可以通过另一个类使用它,这个类是一个类的子类,而这个类是一个类的子类 class MyDescriptorClass(object): def __init__(self, owner, name, activates = 0): self.value = None self.name = name self.owner = owner self.activates = 0 self
class MyDescriptorClass(object):
def __init__(self, owner, name, activates = 0):
self.value = None
self.name = name
self.owner = owner
self.activates = 0
self.connects = []
def __set__(self, obj, val):
self.set(val)
def __get__(self, instance, owner):
return self.value
def set(self, value):
if self.value == value:
return 0
self.value = value
if self.activates:
self.owner.evaluate()
def connect(self, inputs):
if not isinstance(inputs, list):
inputs = list(inputs)
for input in inputs:
self.connects.append(input)
class ParentClass(object):
def __init__(self, name):
self.states = {}
self.name = name
self.A = MyDescriptorClass(self, name, activates = 1)
self.B = MyDescriptorClass(self, name, activates = 1)
self.states.setDefault('A', self.A)
self.states.setDefault('B', self.B)
class ChildClass1(ParentClass):
def __init__(self, name)
super(ChildClass1, self).__init__(name)
self.ans = None
def evaluate(self):
self.ans = self.A.value + self.B.value
class ChildClass2(ParentClass):
def __init__(self, name)
super(ChildClass1, self).__init__(name)
self.ans = None
def evaluate(self):
self.ans = self.A.value * self.B.value
self.A=MyDescriptorClass()
将无法根据
因此,唯一的方法是将ParentClass
中的A=MyDescriptorClass()
定义为
class ParentClass(object):
A = MyDescriptorClass() # here I am unable to pass the owner
由于我使用的是一个子类,super
call跳过这一部分,直接从\uuuuu init\uuuuuu
是否有任何方法可以修改设计,以便直接设置ChildClass1.A
实例的值
c = ChildClass1("c1")
c.A = 10 # I directly want to set this value instead of using c.A.set(10)
c.B = 20
c.evaluate()
print c.ans # 30
c.B = 40
print c.ans # 50
正如他所评论的:
描述符必须是类属性,而不是实例属性才能工作-
因此,首先:
class ParentClass(object):
A = MyDescriptorClass()
B = MyDescriptorClass()
def __init__(self, name):
self.states = {}
self.name = name
self.A.configure(self, name, activates = 1)
self.B.configure(self, name, activates = 1)
self.states.setDefault('A', self.A)
self.states.setDefault('B', self.B)
然后相应地修复描述符类:
然后在实例本身中保留引用实例的所有数据
(这就是为什么\uuuuu获取\uuuuu
和\uu设置\uuuuu
接收对象本身)-或者
每个描述符实例都有一个字典,可以在其中注释相关数据
它们也属于类的实例,例如,通过对象ID
您的描述符类可以大致如下所示:
class MyDescriptorClass(object):
def __init__(self):
self.data = defaultDict(dict)
def configure(self, owner, name, activates = 0):
container = self.data(id(owner))
container["value"] = None
container["name"] = name
...
def __set__(self, owner, value):
# implemnt your previous "set" method straight here
...
...
尽量不要将特定于实例的信息放在描述符中。在实例属性中保留特定于实例的信息,并在描述符中保留特定于描述符的信息(如
激活
):
class MyDescriptorClass(object):
def __init__(self, activates = 0):
self.value = None
self.activates = activates
self.connects = []
def __set__(self, instance, val): # 1
if self.value == val:
return 0
self.value = val
if self.activates:
instance.evaluate()
def __get__(self, instance, instcls): # 1
return self.value
\uuuuuuuuuuuuuuuu
和\uuuuuuuuu
方法通过
正在访问描述符的实例。因此,你不需要
需要在MyDescriptor中存储所有者
。实例是
所有者
鉴于在下面的评论中对问题的澄清,下面是我将如何实现描述符
class GateInput(object):
def __init__(self, index):
self.index = index # 4
def __get__(self, inst, instcls):
return inst.inputs[self.index].ans # 5
def __set__(self, inst, val):
if isinstance(val, (float, int)):
inst.inputs[self.index] = Constant(val)
else:
inst.inputs[self.index] = val
class Constant(object):
def __init__(self, val):
self.ans = val
class Gate(object):
A = GateInput(0) # 1
B = GateInput(1) # 1
def __init__(self, name):
self.name = name
self.inputs = [Constant(0), Constant(0)] # 2
class Adder(Gate):
@property
def ans(self):
result = 0
for gate in self.inputs:
result += gate.ans # 3
return result
class Multiplier(Gate):
@property
def ans(self):
result = 1
for gate in self.inputs:
result *= gate.ans
return result
b = Multiplier('b1')
b.A = 2
b.B = 3
print(b.A)
# 2
print(b.ans)
# 6
c = Adder('c1')
c.A = 10
print(c.ans)
# 10
# This connects output of b to an input of c
c.B = b
print(c.ans)
# 16
\uuuu init\uuuu
中的描述符门
,
gate.ans
需要返回一个值GateInput
是
连接到c.A
导致Python
调用GateInput.\uuuu获取(self,c,type(c))
。因此,inst
是c
在这里所以你需要所有者是
父类而不是绑定到的类?我不确定我是否理解你的问题;不,您不能将描述符设置为实例属性,它们必须驻留在类中。但我不清楚您试图用描述符实现什么。子类将从其父类层次结构继承描述符,因此self。如果A
是类属性,则ChildClass2
上将提供A
。您的描述符直接在描述符实例上设置值;您可能想在所有者实例上设置它们。我正在尝试这个。但它将self.A
显示为NoneType
对象,并抛出AttributeError
这很好。但是,我无法使用connect
。c=儿童类别1(“c1”);b=儿童2级(“b1”);c、 A.连接(b.A);这会给出AttributeError
,即NoneType
对象没有属性connect
是否希望connects
列表与实例c
关联(即每个实例是否有不同的connects
列表),或者您想让所有的父类
实例潜在地改变相同的连接
列表吗?连接
列表与MyDescriptClass
有什么关系?它在那里干什么?将connect
方法放在ParentClass
中不是更有意义吗?我正在制作类似逻辑电路的东西。因此ParentClass
这里是Gate
,有2个输入值和1个输出值和Gate
将是这个类的子类。而描述符class
用于连接。因此,如果门1的输出转到门2的输入A。