【问题标题】:How to add multiple similar properties in Python如何在 Python 中添加多个相似的属性
【发布时间】:2014-02-26 04:01:06
【问题描述】:

我正在构建一个模拟器,它将模拟各种类型的实体。所以我有一个基类ModelObject,并将为所有不同的实体使用子类。每个实体都有一组我想要跟踪的属性,所以我还有一个名为 RecordedDetail 的类,它跟踪更改(基本上构建一个 (time_step, value) 对的列表)和每个 @ 987654323@ 有一个 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()

这是一个改进,但仍然有很多打字。

所以,有几个问题。

  1. 我可以在RecordedDetail 类中添加描述符内容(__get____set__ 等)吗?这样做有什么好处吗?

  2. 有什么方法可以在两个不同的地方输入少于三遍的新属性名称(例如“级别”)?

  3. 我是不是完全找错树了?

【问题讨论】:

    标签: python properties descriptor


    【解决方案1】:

    最后一段代码在正确的轨道上。您可以通过使用元类为列表中的每个项目创建一个命名的 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 中使用上述模式

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-21
      • 2015-09-14
      • 1970-01-01
      • 2021-01-18
      • 2016-07-02
      • 2016-05-22
      • 2017-11-22
      相关资源
      最近更新 更多