简体   繁体   中英

Using the key in collections.defaultdict

collections.defaultdict is great. Especially in conjunction with lambda :

>>> import collections
>>> a = collections.defaultdict(lambda : [None,None])
>>> a['foo']
[None, None]

Is there a way to use the key given (eg 'foo' ) in the lambda? For example (doesn't work):

>>> a = collections.defaultdict(lambda : [None]*key)
>>> a[1]
[None]
>>> a[2]
[None, None]
>>> a
defaultdict(<function <lambda> at 0x02984170>, {1: [None], 2: [None, None]})

You probably want __missing__ which is called on dict whenever you try to access an item not present in the dict; the vanilla __missing__ raises an exception, but you could do whatever you like in a subclass:

class A(dict):
    def __missing__(self, key):
        value = self[key] = [None] * key
        return value

Combining the answers from SingleNegationElimination and rplnt , and the defaultdict documentation , I used the following solution.

import collections
class KeyBasedDefaultDict(collections.defaultdict):
    def __missing__(self, key):
        if self.default_factory is None:
            raise KeyError(key)
        self[key] = self.default_factory(key)
        return self[key]

The body of the method could possibly just be return self.default_factory(key) , but the extra code makes sure to replicate all defaultdict behaviour.

Usage as described in question:

d = KeyBasedDefaultDict(lambda key: [None] * key)
d[1]
> [None]
d[2]
> [None, None]

This will work as requested, although it's probably not the best solution (you need to initialize it with default call and then not use it). It could probably be fixed with overriding some other method(s).

class NoneDict(collections.defaultdict):
    def __setitem__(self, key, value):
        super(NoneDict, self).__setitem__(key, key*[None])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM