Словарь Python, который по умолчанию является ключом?

Есть ли способ получить defaultdict для возврата ключа по умолчанию? Или какая-то структура данных с аналогичным поведением? То есть, после инициализации словаря d,

>>> d['a'] = 1
>>> d['a']
1
>>> d['b']
'b'
>>> d['c']
'c'

Я видел только словари по умолчанию, использующие функции, не принимающие параметров, поэтому я не уверен, есть ли другое решение, кроме создания нового типа словаря.


person beardc    schedule 29.05.2012    source источник
comment
Это слишком узкая задача. Я предлагаю вам рассмотреть возможность создания подкласса объекта / типа 'dict'.   -  person heltonbiker    schedule 29.05.2012
comment
Я заинтригован этим. Можете ли вы дать представление о том, для чего вам это нужно?   -  person Ben Butler-Cole    schedule 29.05.2012


Ответы (4)


Я бы переопределил __missing__ метод dict:

>>> class MyDefaultDict(dict):
...     def __missing__(self, key):
...         self[key] = key
...         return key
...
>>> d = MyDefaultDict()
>>> d['joe']
'joe'
>>> d
{'joe': 'joe'}
person pillmuncher    schedule 29.05.2012
comment
Есть ли особая причина хранить ключ в дополнение к его возврату? Если мне не нужно знать, какие ключи были запрошены, я не вижу причин для этого. - person Joachim Sauer; 29.05.2012
comment
@JoachimSauer: Обычно ожидается, что если d['joe'] не поднимает KeyError, тогда 'joe' in d оценивается как True. Если бы я не хранил ключ, этого не было бы. - person pillmuncher; 29.05.2012
comment
Но это решение заставляет 'joe' in d оценивать False , если вы не использовали d['joe'] до. Таким образом, чистый доступ только для чтения изменяет результат другого доступа только для чтения. Не уверен, что это лучше. - person Joachim Sauer; 29.05.2012
comment
@JoachimSauer: Вы правы, но хранение ключа согласуется с тем, как работает collections.defaultdict. - person pillmuncher; 29.05.2012

Изменить: Ой, я только что понял, что код в моем файле изначально был получен из другого ответа stackoverflow! https://stackoverflow.com/a/2912455/456876, проголосуйте за него.

Это то, что я использую - это вариант defaultdict, который передает ключ в качестве аргумента фабричной функции значения по умолчанию, которая передается в качестве аргумента в init, а не без аргументов:

class keybased_defaultdict(defaultdict):
    def __missing__(self, key):
        if self.default_factory is None:
            raise KeyError(key)
        else:
            value = self[key] = self.default_factory(key)
            return value

Это то, что вам нужно:

>>> d = keybased_defaultdict(lambda x: x)
>>> d[1]
1
>>> d['a']
'a'

Другие возможности:

>>> d = keybased_defaultdict(lambda x: len(x))
>>> d['a']
1
>>> d['abc']
3
person weronika    schedule 29.05.2012
comment
Я был несколько удивлен, когда [повторно] обнаружил, что defaultdict уже не работает так ... - person ; 29.05.2012
comment
@pst Я полагаю, что теоретически это имеет некоторый смысл, что не поведение по умолчанию - если вы сохраняете одну и ту же информацию в ключе и значении, вы можете использовать неправильный тип данных. Тем не менее, я использую это в своих программах на работе. - person weronika; 29.05.2012

Если вы не хотите создавать подклассы dict, вы можете попробовать использовать

d.get('a', 'a')
d.get('b', 'b')
d.get('c', 'c')

Что мне кажется более ясным и менее волшебным для этой цели

Если вы фанатик DRY и у вас только одна символьная клавиша, вы можете это сделать :)

d.get(*'a'*2)
d.get(*'b'*2)
d.get(*'c'*2)
person John La Rooy    schedule 29.05.2012

Скорее всего, вам придется написать свой собственный класс, который наследует (или похож на) defaultdict и переопределяет метод __getitem__.

person inspectorG4dget    schedule 29.05.2012