3

最小限のタイピング作業でオンザフライで作成でき、非常に読みやすいポリモーフィック構造を作成したいと考えています。例えば:

a.b = 1
a.c.d = 2
a.c.e = 3
a.f.g.a.b.c.d = cucu
a.aaa = bau

次のような中間コンテナを作成したくありません。

a.c = subobject()
a.c.d = 2
a.c.e = 3

私の質問はこれに似ています:

ネストされた辞書を実装する最良の方法は何ですか?

しかし、バグがあると思うので、そこの解決策には満足していません:
アイテムは、必要のない場合でも作成されます:2つのポリモーフィック構造を比較したいとします:2番目の構造に、存在する属性が作成されます1 つはチェックインされ、もう 1 つはチェックインされます。例えば:

a = {1:2, 3: 4}
b = {5:6}

# now compare them:

if b[1] == a[1]
    # whoops, we just created b[1] = {} !

また、可能な限り簡単な表記法を取得したい

a.b.c.d = 1
    # neat
a[b][c][d] = 1
    # yuck

私はオブジェクトクラスから派生しようとしました...しかし、それらを読み取ろうとするだけで属性が生まれた上記と同じバグを残すことは避けられませんでした:単純な dir() は「メソッド」のような属性を作成しようとします...この例のように、明らかに壊れています:

class KeyList(object):
    def __setattr__(self, name, value):
        print "__setattr__ Name:", name, "value:", value
        object.__setattr__(self, name, value)
    def __getattribute__(self, name):
        print "__getattribute__ called for:", name
        return object.__getattribute__(self, name)
    def __getattr__(self, name):
        print "__getattr__ Name:", name
        try:
            ret = object.__getattribute__(self, name)
        except AttributeError:
            print "__getattr__ not found, creating..."
            object.__setattr__(self, name, KeyList())
            ret = object.__getattribute__(self, name)
        return ret

>>> cucu = KeyList()
>>> dir(cucu)
__getattribute__ called for: __dict__
__getattribute__ called for: __members__
__getattr__ Name: __members__
__getattr__ not found, creating...
__getattribute__ called for: __methods__
__getattr__ Name: __methods__
__getattr__ not found, creating...
__getattribute__ called for: __class__

ありがとう、本当に!

ps:これまでに見つけた最良の解決策は次のとおりです。

class KeyList(dict):
    def keylset(self, path, value):
        attr = self
        path_elements = path.split('.')
        for i in path_elements[:-1]:
            try:
                attr = attr[i]
            except KeyError:
                attr[i] = KeyList()
                attr = attr[i]
        attr[path_elements[-1]] = value

# test
>>> a = KeyList()
>>> a.keylset("a.b.d.e", "ferfr")
>>> a.keylset("a.b.d", {})
>>> a
{'a': {'b': {'d': {}}}}

# shallow copy
>>> b = copy.copy(a)
>>> b
{'a': {'b': {'d': {}}}}
>>> b.keylset("a.b.d", 3)
>>> b
{'a': {'b': {'d': 3}}}
>>> a
{'a': {'b': {'d': 3}}}

# complete copy
>>> a.keylset("a.b.d", 2)
>>> a
{'a': {'b': {'d': 2}}}
>>> b
{'a': {'b': {'d': 2}}}
>>> b = copy.deepcopy(a)
>>> b.keylset("a.b.d", 4)
>>> b
{'a': {'b': {'d': 4}}}
>>> a
{'a': {'b': {'d': 2}}}
4

2 に答える 2

1

元の投稿ほど動的ではないが、これまでの最善のソリューションに近いものを探している場合は、Ian Bicking のformencodevariabledecodeがニーズを満たすかどうかを確認できます。パッケージ自体はWeb フォームと検証を目的としていますが、いくつかのメソッドは探しているものにかなり近いようです。
他に何もない場合でも、独自の実装の例として役立つ可能性があります。

小さな例:

>>> from formencode.variabledecode import variable_decode, variable_encode
>>>
>>> d={'a.b.c.d.e': 1}
>>> variable_decode(d)
{'a': {'b': {'c': {'d': {'e': 1}}}}}
>>>
>>> d['a.b.x'] = 3
>>> variable_decode(d)
{'a': {'b': {'c': {'d': {'e': 1}}, 'x': 3}}}
>>>
>>> d2 = variable_decode(d)
>>> variable_encode(d2) == d
True
于 2010-10-18T18:04:33.023 に答える
1

__getattr__少なくとも、要求された属性が で開始および終了していないことを確認する必要があると思います__。その説明に一致する属性は、確立された Python API を実装するため、これらの属性をインスタンス化するべきではありません。それでも、たとえば のようないくつかの API 属性を実装することになりますnext。その場合、オブジェクトをダックタイピングを使用してイテレータであるかどうかを確認する関数に渡すと、例外がスローされることになります。

リテラル セットとして、または単純な式を使用して、有効な属性名の「ホワイトリスト」を作成することをname.isalpha() and len(name) == 1お勧めします。たとえば、例で使用している 1 文字の属性に対して機能します。より現実的な実装のために、コードが動作しているドメインに適した一連の名前を定義したいと思うでしょう。

next別の方法は、反復プロトコルの一部であるように、何らかのプロトコルの一部であるさまざまな属性名を動的に作成していないことを確認することだと思います。collectionsモジュール内の ABC のメソッドは部分的なリストで構成されていますが、完全なリストがどこにあるのかわかりません。

また、オブジェクトがそのような子ノードを作成したかどうかを追跡する必要があるため、他のそのようなオブジェクトと比較する方法がわかります。

比較で自動有効化を回避したい場合は、比較対象のオブジェクトのをチェックするクラスにメソッド__cmp__、または豊富な比較メソッドを実装する必要があります。__dict__

私が思いもよらなかったいくつかの複雑な問題があるとこっそり感じていますが、これは Python が実際にどのように機能するかではないため、驚くべきことではありません。慎重に検討し、このアプローチによって複雑さが増すだけの価値があるかどうかを考えてください。

于 2010-10-18T01:18:47.830 に答える