Python defaultdict и лямбда
В другом коде я прочитал следующие две строки:
x = defaultdict(lambda: 0)
y = defaultdict(lambda: defaultdict(lambda: 0))
Поскольку аргумент defaultdict является значением по умолчанию factory, я думаю, что первая строка означает, что когда я вызываю x [k] для несуществующего ключа k (например, выражения типа v = x [k]), ключ -значная пара (k, 0) будет автоматически добавлена в словарь, как если бы сначала выполнялся оператор x [k] = 0. Правильно ли я?
А как насчет у? Кажется, что по умолчанию factory создаст defaultdict с дефолтом 0. Но что это значит конкретно? Я пытался поиграть с ним в оболочке Python, но не мог понять, что именно.
Ответы
Ответ 1
Я думаю, что первая строка означает, что, когда я вызываю x[k]
для несуществующего ключа k
(например, для выражения типа v=x[k]
), пара ключ-значение (k,0)
будет автоматически добавлена в словарь, как будто сначала выполняется инструкция x[k]=0
.
Это правильно. Это более идиоматически написано
x = defaultdict(int)
В случае y
, когда вы делаете y["ham"]["spam"]
, ключ "ham"
вставляется в y
, если он не существует. Значение, связанное с ним, становится defaultdict
, в котором "spam"
автоматически вставляется со значением 0
.
I.e., y
является своего рода "двухуровневым" defaultdict
. Если "ham" not in y
, то оценка y["ham"]["spam"]
аналогична выполнению
y["ham"] = {}
y["ham"]["spam"] = 0
в терминах обычного dict
.
Ответ 2
defaultdict
принимает нулевой аргумент, вызываемый его конструктору, который вызывается, когда ключ не найден, как вы правильно объяснили.
lambda: 0
, конечно, всегда будет возвращать ноль, но предпочтительный способ сделать это defaultdict(int)
, который будет делать то же самое.
Что касается второй части, автор хотел бы создать новый defaultdict(int)
или вложенный словарь, всякий раз, когда ключ не найден в словаре верхнего уровня.
Ответ 3
Вы правы в том, что делает первый. Что касается y
, он создаст defaultdict со значением по умолчанию 0, если ключ не существует в y
, поэтому вы можете думать об этом как вложенном словаре. Рассмотрим следующий пример:
y = defaultdict(lambda: defaultdict(lambda: 0))
print y['k1']['k2'] # 0
print dict(y['k1']) # {'k2': 0}
Чтобы создать эквивалентную вложенную структуру словаря без defaultdict, вам нужно создать внутренний dict для y['k1']
, а затем установить y['k1']['k2']
в 0, но defaultdict делает все это за кулисами, когда он сталкивается с ключами, видел:
y = {}
y['k1'] = {}
y['k1']['k2'] = 0
Следующая функция может помочь поиграть с этим на интерпретаторе, чтобы лучше понять:
def to_dict(d):
if isinstance(d, defaultdict):
return dict((k, to_dict(v)) for k, v in d.items())
return d
Это вернет dict-эквивалент вложенного defaultdict, который намного легче читать, например:
>>> y = defaultdict(lambda: defaultdict(lambda: 0))
>>> y['a']['b'] = 5
>>> y
defaultdict(<function <lambda> at 0xb7ea93e4>, {'a': defaultdict(<function <lambda> at 0xb7ea9374>, {'b': 5})})
>>> to_dict(y)
{'a': {'b': 5}}
Ответ 4
y = defaultdict(lambda:defaultdict(lambda:0))
будет полезно, если вы попробуете этот y['a']['b'] += 1
Ответ 5
Все ответы достаточно хороши, но я даю ответ, чтобы добавить дополнительную информацию:
"defaultdict требует аргумента, который может быть вызван. Возвращаемый результат этого вызываемого объекта является значением по умолчанию, которое словарь возвращает при попытке доступа к словарю с ключом, который не существует.
Здесь пример
SAMPLE= {'Age':28, 'Salary':2000}
SAMPLE = defaultdict(lambda:0,SAMPLE)
>>> SAMPLE
defaultdict(<function <lambda> at 0x0000000002BF7C88>, {'Salary': 2000, 'Age': 28})
>>> SAMPLE['Age']----> This will return 28
>>> SAMPLE['Phone']----> This will return 0 # you got 0 as output for a non existing key inside SAMPLE