2016-06-06 89 views
1

我在尋找一個優雅(一種有效的)的方式來實現以下Python列表的變化:反映在字符串屬性

我有一個類存儲值的列表作爲字符串(帶分隔,例如。:「 - 」)。我使用一個屬性(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" 
+4

爲什麼不存儲列表並生成字符串,而不是反過來呢? – BrenBarn

+0

如何'c.value_list + = 「四個一」]'? –

+0

@BrenBam:其實我大大簡化問題。我從解析數據(一個文件)中獲得** string **值。有些值是標量/非可變數據(這裏沒有問題),但有些值代表集合。我選擇最常見的一個:**列表**。 –

回答

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' 
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

+0

當然,你可以添加運營商的一個例子。但是這個解決方案不是通用的。像''_values''這樣的多個屬性怎麼樣? –