类似于PERL的自动修复,在Python中使用默认值,并从不存在的任意嵌套返回默认值?

时间:2014-06-30 04:17:16

标签: python dictionary recursion defaultdict autovivification

假设我想在Python中使用类似PERL的自动修复,即:

>>> d = Autovivifier()
>>> d = ['nested']['key']['value']=10
>>> d
{'nested': {'key': {'value': 10}}}

有几种主要方法可以做到这一点:

  1. Use a recursive default dict
  2. Use a __missing__ hook to return the nested structure
  3. 好的 - 容易。

    现在假设我想从缺少密钥的dict返回默认值。再一次,没有办法做到这一点:

    1. 对于非嵌套路径,您可以use a __missing__ hook
    2. 尝试/禁止阻止访问可能缺少的密钥路径
    3. 使用{}.get(key, default) (does not easily work with a nested dict),即autoviv.get(['nested']['key']['no key of this value'], default)
    4. 没有版本

      这两个目标似乎是不可调和的冲突(基于我试图在过去几个小时内解决这个问题。)

      以下是问题:

      假设我想要一个Autivivifying dict,1)为d['arbitrary']['nested']['path']创建嵌套结构; AND 2)从不存在的任意嵌套中返回一个默认值,而不将其包装在try / except中?

      以下是问题:

      1. d['nested']['key']['no key of this value'] is equivalent to (d['nested'])['key']['no key of this value']的来电。如果没有返回覆盖__getitem__的对象,则覆盖__getitem__不起作用。
      2. 如果您测试该路径是否存在,那么创建Autovivifier的方法都将创建一个dict条目。即,如果您只是使用if d['p1']['sp2']['etc.']测试它,我不希望if创建整个路径。
      3. 我如何在Python中提供一个dict:

        1. 创建d['p1']['p2'][etc]=val类型的访问路径(Autovivication);
        2. 如果您测试存在,则不创建相同的路径;
        3. 返回默认值(如{}.get(key, default)),不包含在try / except
        4. 我不需要完整的dict操作集。实际上只有d=['nested']['key']['value']=vald['nested']['key']['no key of this value']等于默认值。我希望测试d['nested']['key']['no key of this value']不会创建它,但会接受它。

3 个答案:

答案 0 :(得分:2)

要创建一个递归的词典树,请使用defaultdict并使用技巧:

from collections import defaultdict

tree = lambda: defaultdict(tree)

然后,您可以使用x = tree()创建x。

以上来自@BrenBarn - defaultdict of defaultdict, nested

答案 1 :(得分:2)

不要这样做。只需编写一个具有您想要的操作的类就可以更容易地解决它,甚至在Perl中它也不是一个普遍评估的功能。

但是,使用自定义的autoviv类, 是可能的。您需要__getitem__返回空的autoviv dict ,但不会存储。新的autoviv dict会记住创建它的autoviv dict和key,然后只有在" real"值存储在其中。

由于空dict测试为falsey,因此您可以测试是否存在Perl样式,而无需实际创建中间dicts。

但我不会写出代码,因为我很确定这是一个糟糕的主意。

答案 2 :(得分:1)

虽然它与Python中的字典协议不完全匹配,但您可以通过实现使用变量 getitem 参数的自己的自动生成字典来获得合理的结果。类似于(2.x):

class ExampleVivifier(object):
    """ Small example class to show how to use varargs in __getitem__. """

    def __getitem__(self, *args):
        print args

示例用法是:

>>> v = ExampleVivifier()
>>> v["nested", "dictionary", "path"]
(('nested', 'dictionary', 'path'),)

您可以填写空白,了解如何在此处实现您想要的行为。