我正在构建一个模拟器,它将模拟各种类型的实体。所以我有一个基类ModelObject
,并将为所有不同的实体使用子类。每个实体都有一组我想要跟踪的属性,所以我还有一个名为RecordedDetail
的类,它保留了更改的轨迹(基本上构建了一个(time_step,value)对的列表)和每个ModelObject
都有一个dict
来存储这些内容。所以我有效地获得了
class ModelObject(object):
def __init__(self):
self.details = {}
self.time_step = 0
def get_detail(self, d_name):
""" get the current value of the specified RecordedDetail"""
return self.details[d_name].current_value()
def set_detail(self, d_name, value):
""" set the current value of the specified RecordedDetail"""
self.details[d_name].set_value(value, self.time_step)
class Widget(ModelObject):
def __init__(self):
super().__init__(self)
self.details["level"] = RecordedDetail()
self.details["angle"] = RecordedDetail()
@property
def level(self):
return self.get_detail("level")
@level.setter
def level(self, value):
self.set_detail("level", value)
@property
def angle(self):
return self.get_detail("angle")
@angle.setter
def angle(self):
self.set_detail("angle", value)
这非常重复,我不禁想到必须有一种使用描述符自动化它的方法,但我无法弄清楚如何。我最终得到了
class RecordedProperty(object):
def __init__(self, p_name):
self.p_name = p_name
def __get__(self, instance, owner):
if instance is None:
return self
return instance.get_detail(self.p_name)
def __set__(self, instance, value):
instance.set_detail(self.p_name, value)
class Widget(ModelObject):
level = RecordedProperty("level")
angle = RecordedProperty("angle")
def __init__(self):
super().__init__(self)
self.details["level"] = RecordedDetail()
self.details["angle"] = RecordedDetail()
这有点改进,但仍然有很多打字。
所以,几个问题。
我可以将描述符内容(__get__
,__set__
等)添加到RecordedDetail
类中吗?这样做有什么好处吗?
在两个不同的地方有没有办法输入新属性名称(例如“级别”)少于三次?
或
我是否完全咆哮错误的树?
答案 0 :(得分:2)
最后一段代码是在正确的轨道上。通过使用元类为列表中的每个项创建命名的RecordedProperty和匹配的RecordedDetail,可以使过程变得不那么讨厌。这是一个简单的例子:
class WidgetMeta(type):
def __new__(cls, name, parents, kwargs):
'''
Automate the creation of the class
'''
for item in kwargs['_ATTRIBS']:
kwargs[item] = RecordedProperty(item)
return super(WidgetMeta, cls).__new__(cls, name, parents, kwargs)
class Widget(ModelObject):
_ATTRIBS = ['level', 'angle']
__metaclass__ = WidgetMeta
def __init__(self, *args, **kwargs):
super().__init__(self)
self.Details = {}
for detail in self._ATTRIBS:
self.Details[detail] = RecordedDetail()
子类只需要在_ATTRIBS
中包含不同的数据。
作为替代方案(我认为它更复杂)您可以使用元类来自定义 init ,就像您自定义 new 一样,创建RecordedDetails _ATTRIBS列表。
第三种选择是在第一次访问时在每个实例中创建RecordedDetail。只要你没有为每个属性都有RecordedDetail的代码,即使没有触及RecordedDetail,这也可以正常工作。
警告我对Python3不是很熟悉;我经常在2.7x
中使用上述模式