Python中的嵌套字典,隐式创建不存在的中间容器?

Python中的嵌套字典,隐式创建不存在的中间容器?,python,dictionary,nested,implicit,creation,Python,Dictionary,Nested,Implicit,Creation,我想创建一个多态结构,它可以用最少的输入工作动态创建,并且非常可读。例如: 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 我的问题与此类似: 但我对那里的解决方案不满意,因为我认为有一个bug: 即使您不想要,也将创建项:假设您想要比较两个多态结构:它将在第二个结构中创建第一个结构中存在的任何属性,而在另一个结构

我想创建一个多态结构,它可以用最少的输入工作动态创建,并且非常可读。例如:

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
我的问题与此类似:

但我对那里的解决方案不满意,因为我认为有一个bug:
即使您不想要,也将创建项:假设您想要比较两个多态结构:它将在第二个结构中创建第一个结构中存在的任何属性,而在另一个结构中只检查这些属性。e、 g:

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__
谢谢,真的

p、 s:到目前为止,我找到的最佳解决方案是:

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

我认为您至少需要在
\uuuu getattr\uuuuuuu
中检查请求的attrib不以
\uuuuuuuu
开头和结尾。与该描述匹配的属性实现已建立的Python API,因此您不应该实例化这些属性。即使如此,您最终还是会实现一些API属性,例如
next
。在这种情况下,如果将对象传递给某个函数,该函数使用duck类型查看它是否是迭代器,则会引发异常

最好创建一个有效属性名称的“白名单”,可以是一个文本集,也可以是一个简单的公式:例如,
name。isalpha()和len(name)==1
适用于示例中使用的一个字母属性。对于更现实的实现,您可能希望定义一组适合于代码所在域的名称

我想另一种方法是确保您没有动态创建作为某个协议一部分的各种属性名称,因为
next
是迭代协议的一部分。中的ABC方法包含一个部分列表,但我不知道在哪里可以找到完整的列表

您还必须跟踪对象是否创建了任何此类子节点,以便知道如何与其他此类对象进行比较

如果希望通过比较来避免自动激活,则必须实现
\uuuu cmp\uuuu
方法,或者在检查被比较对象的
\uuu dict\uuuu
的类中实现


我有一种不为人知的感觉,有一些我没有想到的复杂情况,这并不奇怪,因为Python并不是这样工作的。仔细地走,想想这种方法增加的复杂性是否值得你去做。

如果你正在寻找的东西没有你原来的帖子那么有活力,但更像是你目前为止最好的解决方案,你可能会看到Ian Bicking的方法是否能满足你的需要。该软件包本身用于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

你是在问有关集合的问题吗?defaultdict?我添加了一个从dict派生的类的示例。这是我能得到的最接近我想要的。谢谢你的建议,但是你需要能够定义你想要的每个名称,并且不实例化任何引用的名称:-)是的,我认为这是一些其他风险业务的替代方案,您可能正在“实现”一些方法,这些方法可能会导致某些python函数的错误解释。但是,如果您只是将其用作平面数据,并且从不将其传递给任何函数,那么只过滤掉
\uuu name\uuu
s可能就足够了。