Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将'defaultdict'作为常规'dict'公开`_Python_Python 3.x_Wrapper_Defaultdict - Fatal编程技术网

Python 将'defaultdict'作为常规'dict'公开`

Python 将'defaultdict'作为常规'dict'公开`,python,python-3.x,wrapper,defaultdict,Python,Python 3.x,Wrapper,Defaultdict,我使用defaultdict(set)在一个非常大的数据结构中填充一个内部映射。填充后,整个结构(包括映射)将暴露给客户机代码。在这一点上,我不希望任何人修改映射 没有人故意这么做。但有时,客户端代码可能会意外引用不存在的元素。此时,普通字典会引发KeyError,但由于映射是defaultdict,它只会在该键处创建一个新元素(空集)。这很难理解,因为一切都是无声的。但我需要确保这不会发生(语义实际上不会中断,但映射会增长到很大的规模) 我该怎么办?我可以看到这些选择: 在当前和将来的客户机代

我使用
defaultdict(set)
在一个非常大的数据结构中填充一个内部映射。填充后,整个结构(包括映射)将暴露给客户机代码。在这一点上,我不希望任何人修改映射

没有人故意这么做。但有时,客户端代码可能会意外引用不存在的元素。此时,普通字典会引发
KeyError
,但由于映射是
defaultdict
,它只会在该键处创建一个新元素(空集)。这很难理解,因为一切都是无声的。但我需要确保这不会发生(语义实际上不会中断,但映射会增长到很大的规模)

我该怎么办?我可以看到这些选择:

  • 在当前和将来的客户机代码中查找对映射执行字典查找的所有实例,并将其转换为
    mapping.get(k,{})
    。这太可怕了

  • 在数据结构完全初始化后,通过将其转换为
    dict
    “冻结”
    defaultdict
    。(我知道它并没有真正冻结,但我相信客户端代码不会真的编写
    映射[k]=v
    )不雅观,而且性能会受到很大影响

  • defaultdict
    包装到
    dict
    界面中。这样做的优雅方式是什么?但是,我担心性能可能会受到巨大的影响(这种查找在紧密循环中大量使用)

  • 子类
    defaultdict
    并添加一个方法,该方法“关闭”所有
    defaultdict
    功能,使其表现为常规
    dict
    。这是上面3的变体,但我不确定它是否更快。我不知道如果不依赖实现细节是否可行

  • 在数据结构中使用regular
    dict
    ,重写那里的所有代码,首先检查元素是否在字典中,如果不在,则添加它。不太好

  • 文档中提到的
    默认工厂

    如果默认的_factory属性为None,则会引发KeyError 以键作为参数的异常

    如果您只是将defaultdict的默认工厂设置为
    None
    ?例如:

    >>> d = defaultdict(int)
    >>> d['a'] += 1
    >>> d
    defaultdict(<type 'int'>, {'a': 1})
    >>> d.default_factory = None
    >>> d['b'] += 2
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    KeyError: 'b'
    >>> 
    
    >d=defaultdict(int)
    >>>d['a']+=1
    >>>d
    defaultdict(,{'a':1})
    >>>d.默认工厂=无
    >>>d['b']+=2
    回溯(最近一次呼叫最后一次):
    文件“”,第1行,在
    键错误:“b”
    >>> 
    

    不确定这是否是最好的方法,但似乎有效。

    您可以创建一个包含对dict的引用的类,并阻止setitem()


    填充完defaultdict后,只需从中创建一个常规dict:

    my_dict = dict(my_default_dict)
    
    可以选择使用类型注释


    如果默认dict是递归默认dict,请查看哪个使用递归解决方案。

    重写将只使用
    dict.setdefault
    方法。。。没什么大不了的deal@JBernardo你说的是选项4吗?关于
    defaultdict
    我所知道的是,如果需要,它会覆盖
    \uu getitem\uuu
    以添加元素。也许它使用
    setdefault
    方法实现了这一点,也许它不调用
    setdefault
    就直接实现了相同的逻辑。如果不依赖于实施细节,我不能做任何假设,对吗?他指的是你的选项#5。只需在代码中使用data.setdefault()来代替defaultdict,我认为您只需在
    defaultdict
    上调用
    dict
    来编辑就可以了it@inspectorG4dget数据结构的大小超过1 GB,因此复制所有数据(如果我调用
    dict
    ,就会发生这种情况)太贵了。谁知道我提出的解决方案已经作为
    defaultdict
    的一个功能实现了呢?很好的发现。(+1)哇,这太完美了。我希望可以安全地更改现有的
    defaultdict
    对象的
    default\u-factory
    。@max--文档特别说明
    default\u-factory
    是一个可写属性,所以应该是安全的。@max:使用源代码:,(名称、类型、偏移量、标志、doc;
    flags==0
    表示它是可写的)如果它对关键方法使用纯python,那么它不是非常慢吗?对于getitem方法?我不确定与defaultdict的其他方法相比的性能开销,我认为Neal的解决方案最适合您的问题
    my_dict = dict(my_default_dict)