2

以下を実装するためのエレガントな(効率的な)方法を探しています:

値のリストを文字列として格納するクラスがあります(セパレーター付き、例: " - ")。プロパティ (ゲッターとセッター) を使用して、この文字列を 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)

プロパティの取得/設定はOKです:

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

2 に答える 2

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'
于 2016-06-06T20:44:17.747 に答える
1

サポートしたい特定の演算子をオーバーロードすることでこれにアプローチします。たとえば、+= 演算子を定義して__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"

演算子のオーバーロードの詳細については、ドキュメントを参照してください。

于 2016-06-06T19:58:03.210 に答える