Использование ключа в коллекциях .defaultdict - PullRequest
15 голосов
/ 01 ноября 2011

collections.defaultdict отлично. Особенно в сочетании с lambda:

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

Есть ли способ использовать данный ключ (например, 'foo') в лямбде? Например (не работает):

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

Ответы [ 3 ]

31 голосов
/ 01 ноября 2011

Вы, вероятно, хотите __missing__, который вызывается на dict всякий раз, когда вы пытаетесь получить доступ к элементу, отсутствующему в dict; Ваниль __missing__ вызывает исключение, но вы можете делать все что угодно в подклассе:

class A(dict):
    def __missing__(self, key):
        value = self[key] = [None] * key
        return value
2 голосов
/ 24 июня 2017

Объединяя ответы от SingleNegationElimination и rplnt и документации по умолчанию , я использовал следующее решение.

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]

Возможно, тело метода может быть просто return self.default_factory(key), но дополнительный код обязательно повторяет все поведение defaultdict.

Использование, как описано в вопросе:

d = KeyBasedDefaultDict(lambda key: [None] * key)
d[1]
> [None]
d[2]
> [None, None]
1 голос
/ 01 ноября 2011

Это будет работать в соответствии с запросом, хотя, вероятно, это не лучшее решение (вам нужно инициализировать его с помощью вызова по умолчанию, а затем не использовать).Возможно, это можно исправить с помощью переопределения других методов.

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