Как использовать конкретную структуру данных в качестве default_factory для defaultdict?
Я в настоящее время использую defaultdict
из Counter
чтобы однозначно подсчитать несколько непредсказуемых значений для непредсказуемых ключей:
from collections import defaultdict, Counter
d = defaultdict(Counter)
d['x']['b'] += 1
d['x']['c'] += 1
print(d)
Это дает мне ожидаемый результат:
defaultdict(<class 'collections.Counter'>, {'x': Counter({'c': 1, 'b': 1})})
Теперь мне нужно расширить структуру значений в defaultdict
и сделать это dict
с двумя ключами: предыдущий Counter
и str
:
mystruct = {
'counter': collections.Counter(),
'name': ''
}
Можно ли использовать конкретную структуру данных (например, выше) в качестве default_factory
в defaultdict
? Ожидаемый результат будет таким, что для каждого несуществующего ключа в defaultdict
, новый ключ и значение, инициализированные с вышеупомянутой структурой, будут созданы.
2 ответа
Вам просто нужно определить свой default_factory как функцию, которая возвращает словарь, в который вы хотите установить значение по умолчанию:
from collections import defaultdict, Counter
d = defaultdict(lambda: {'counter': Counter(), 'name': ''})
d['x']['counter']['b'] += 1
d['x']['counter']['c'] += 1
print(d)
Если вы не знакомы с лямбдами, это то же самое, что и:
def my_factory():
aDict = {'counter': Counter(), 'name':''}
return aDict
d = defaultdict(my_factory)
Альтернативное решение ответа drootang- использовать пользовательский класс:
from collections import defaultdict, Counter
class NamedCounter:
def __init__(self, name = '', counter = None):
self.counter = counter if counter else Counter()
self.name = name
def __repr__(self):
return 'NamedCounter(name={}, counter={})'.format(
repr(self.name), repr(self.counter))
d = defaultdict(NamedCounter)
d['x'].counter['b'] += 1
d['x'].counter['b'] += 1
d['x'].name = 'X counter'
print(d)
defaultdict (
, {'x': NamedCounter (name = 'X counter', counter = Counter ({'b': 2}))})
Кроме того, вы можете продлить Counter
включить имя в сам счетчик:
from collections import defaultdict, Counter
class NamedCounter(Counter):
def __init__(self, name = '', dict = None):
super(Counter, self).__init__(dict if dict else {})
self.name = name
def __repr__(self):
return 'NamedCounter(name={}, dict={})'.format(
repr(self.name), super(Counter, self).__repr__())
d = defaultdict(NamedCounter)
d['x']['b'] += 1
d['x']['b'] += 1
d['x'].name = 'X counter'
print(d)
defaultdict (
, {'x': NamedCounter (name = 'X counter', dict = {'b': 2})})