反映字符串属性中的Python列表更改

时间:2016-06-06 19:51:09

标签: python properties python-descriptors

我正在寻找一种优雅(高效)的方式来实现以下目标:

我有一个类将值列表存储为字符串(带分隔符,例如:“ - ”)。我使用属性(getter和setter)将此字符串转换为Python list

class C(object):
    def __init__(self, values):
        """
        Construct C with a string representing a list of values.

        :type values: str
        :param values: List of values
        """
        self.values = values

    @property
    def value_list(self):
        """ Values as list """
        return self.values.split(" - ")

    @value_list.setter
    def value_list(self, seq):
        self.values = " - ".join(seq)

获取/设置属性是正常的:

c = C("one - two")
assert c.value_list == ["one", "two"]

c.value_list = ["one", "two", "three"]
assert c.values == "one - two - three"

但我正在寻找一些东西(可能是另一种列表)来自动反映list中的变化。

c.value_list.append("four")
assert c.values == "one - two - three - four"

Traceback (most recent call last):
...
AssertionError

目前,我使用回调系统实现了我自己的list类继承collections.MutableSequence。 有没有更好的方法呢?

编辑:我当前的解决方案

我使用列表和“on_change”处理程序,如下所示:

class MyList(collections.MutableSequence):
    """ A ``list`` class with a "on_change" handler. """

    def __init__(self, *args):
        self._list = list(*args)

    def on_change(self, seq):
        pass

    def __getitem__(self, index):
        return self._list.__getitem__(index)

    def __len__(self):
        return self._list.__len__()

    def __setitem__(self, index, value):
        self._list.__setitem__(index, value)
        self.on_change(self._list)

    def __delitem__(self, index):
        self._list.__delitem__(index)
        self.on_change(self._list)

    def insert(self, index, value):
        self._list.insert(index, value)
        self.on_change(self._list)

然后我需要修改我的C类来实现这个处理程序以反映更改。

该课程的新版本是:

class C(object):
    def __init__(self, values):
        """
        Construct C with a string representing a list of values.

        :type values: str
        :param values: List of values
        """
        self.values = values

    def _reflect_changes(self, seq):
        self.values = " - ".join(seq)

    @property
    def value_list(self):
        """ Values as list """
        my_list = MyList(self.values.split(" - "))
        my_list.on_change = self._reflect_changes
        return my_list

    @value_list.setter
    def value_list(self, seq):
        self.values = " - ".join(seq)

这样,列表中的任何更改都会反映在values属性中:

c = C("one - two")

c.value_list.append("three")
assert c.values == "one - two - three"

c.value_list += ["four"]
assert c.values == "one - two - three - four"

2 个答案:

答案 0 :(得分:1)

我会通过重载您想要支持的某些运算符来解决此问题,例如+= operator by defining __iadd__。然后,您就可以执行以下操作:

class C(object):
    def __init__(self, values):
        self._values = values

    def __iadd__(self, value):
        self._values += " - " + str(value)
        return self

obj = C("one - two")
obj += "three"

print(obj.values) # "one - two - three"

有关运算符重载的详细信息,请参阅docs

答案 1 :(得分:1)

也许我过度简化了您的问题,因为您已经过度简化了您的第一个例子,但我会同意一些评论者并建议您改变存储方式。 存储列表,根据需要生成字符串。

In [1]: class C(object):
   ...:     def __init__(self, values):
   ...:         self.values = values.split(' - ')
   ...:     @property
   ...:     def value_str(self):
   ...:         return ' - '.join(self.values)
   ...:

In [2]: c = C('one - two - three')

In [3]: c.values
Out[3]: ['one', 'two', 'three']

In [4]: c.values.append('four')

In [5]: c.value_str
Out[5]: 'one - two - three - four'