【问题标题】:Accessing key in factory of defaultdict访问 defaultdict 工厂中的密钥
【发布时间】:2013-10-24 07:24:31
【问题描述】:

我正在尝试做类似的事情:

from   collections import defaultdict
import hashlib

def factory():
    key = 'aaa'
    return { 'key-md5' : hashlib.md5('%s' % (key)).hexdigest() }

a = defaultdict(factory)
print a['aaa']

(实际上,我需要访问工厂中的密钥的原因不是为了计算md5,而是出于其他原因;这只是一个例子)

如您所见,在工厂中我无法访问密钥:我只是在强制它,这没有任何意义。

是否可以以我可以在工厂访问密钥的方式使用defaultdict?

【问题讨论】:

  • 出于好奇,为什么需要defaultdict,只是为了纠正缺失值吗?因为除了返回{}之外,这就是它所做的一切?
  • 是的,它是为字典中缺少的键提供值。这就是defaultdict 的全部意义,不是吗?问题是我存储在 defaultdict 中的(真实)数据结构具有取决于键的字段。因此,每当我试图访问一个不存在的元素时,我需要在工厂中使用defaultdict 的键作为参数来创建它。
  • 害怕你做的事情比平常多一点。请参阅@falsetru 的解决方案,因为这是我在自定义构建字典使用的情况下向您建议的:)

标签: python python-2.7 dictionary defaultdict


【解决方案1】:

在我想要一个带有工厂密钥的 defaultdict 的情况下,我发现 lru_cache 也解决了我的问题:

import functools

@functools.lru_cache(maxsize=None)
def use_func_as_dict(key='') # Or whatever type
    with open(key, 'r') as ifile:
        return ifile.readlines()

f1 = use_func_as_dict('test.txt')
f2 = use_func_as_dict('test2.txt')
# This will reuse the old value instead of re-reading the file
f3 = use_func_as_dict('test.txt')
assert f3 is f1

这实际上在理论上更有意义,因为您追求的是输入的函数,而不是一致的虚拟后备。

【讨论】:

    【解决方案2】:

    defaultdict 的__missing__ 不会将key 传递给工厂函数。

    如果default_factory 不是None,则调用无参数 为给定键提供默认值,该值被插入 键的字典,并返回。

    使用自定义__missing__ 方法制作您自己的字典类。

    >>> class MyDict(dict):
    ...     def __init__(self, factory):
    ...         self.factory = factory
    ...     def __missing__(self, key):
    ...         self[key] = self.factory(key)
    ...         return self[key]
    ... 
    >>> d = MyDict(lambda x: -x)
    >>> d[1]
    -1
    >>> d
    {1: -1}
    

    【讨论】:

    • 我还是不明白为什么defaultdict不支持这种类型的工厂。谁能解释一下?
    • @midas 我不确定,但我的猜测是没有很好的方法来做到这一点,同时保持使用不需要参数的构造函数插入任何类型的能力(@ 987654329@, defaultdict(MyClass))。
    • @ralokt,谁能解释一下为什么要使用工厂而不是对象,例如defaultdict(0)?
    • @Alexey 因为有时静态值不会削减它,这是我的猜测。这比不传递丢失的密钥更糟糕,因为它没有任何东西可以传递给它。此外,具有可变类型的静态值将是完全不行的,每个缺失的键都将指向同一个对象。
    • 我同意无法访问key 是愚蠢的。对于不需要密钥的情况,您可以简单地忽略它,例如defaultdict(lambda key: 0)
    【解决方案3】:

    不幸的是,不能直接调用,因为 defaultdict 指定 default_factory 必须在不带参数的情况下调用:

    http://docs.python.org/2/library/collections.html#collections.defaultdict

    但可以使用 defaultdict 作为具有您想要的行为的基类:

    class CustomDefaultdict(defaultdict):
        def __missing__(self, key):
            if self.default_factory:
                dict.__setitem__(self, key, self.default_factory(key))
                return self[key]
            else:
                defaultdict.__missing__(self, key)
    

    这对我有用:

    >>> a = CustomDefaultdict(factory)
    >>> a
    defaultdict(<function factory at 0x7f0a70da11b8>, {})
    >>> print a['aaa']
    {'key-md5': '47bce5c74f589f4867dbd57e9ca9f808'}
    >>> print a['bbb']
    {'key-md5': '08f8e0260c64418510cefb2b06eee5cd'}
    

    【讨论】:

    • 不需要使用defaultdict作为基类:since Python 2.2dict可以直接子类化。
    猜你喜欢
    • 2011-01-15
    • 2020-08-25
    • 1970-01-01
    • 2017-03-23
    • 2021-12-25
    • 1970-01-01
    • 2019-10-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多