Python defaultdict и лямбда - PullRequest
       29

Python defaultdict и лямбда

46 голосов
/ 07 декабря 2011

В чужом коде я читаю следующие две строки:

x = defaultdict(lambda: 0)
y = defaultdict(lambda: defaultdict(lambda: 0))

Поскольку аргумент defaultdict является фабрикой по умолчанию, я думаю, что первая строка означает, что когда я вызываю x [k] для несуществующегоключ k (например, оператор типа v = x [k]), пара ключ-значение (k, 0) будет автоматически добавлена ​​в словарь, как если бы сначала выполнялся оператор x [k] = 0.Я прав?

А что у?Кажется, что фабрика по умолчанию создаст defaultdict со значением по умолчанию 0. Но что это означает конкретно?Я пытался поиграть с ним в оболочке Python, но не смог понять, что это такое.

Ответы [ 5 ]

44 голосов
/ 07 декабря 2011

Я думаю, что первая строка означает, что когда я вызываю x[k] для несуществующего ключа k (например, такого как v=x[k]), пара ключ-значение (k,0) будет автоматически добавлена ​​в словарь, как будто сначала выполняется оператор x[k]=0.

Это верно. Это более идиоматически написано

x = defaultdict(int)

В случае y, когда вы делаете y["ham"]["spam"], ключ "ham" вставляется в y, если он не существует. Значение, связанное с ним, становится defaultdict, в котором "spam" автоматически вставляется со значением 0.

Т.е.. y - это разновидность "двухуровневой" defaultdict. Если "ham" not in y, то оценка y["ham"]["spam"] аналогична

y["ham"] = {}
y["ham"]["spam"] = 0

в пересчете на обычные dict.

7 голосов
/ 07 декабря 2011

Вы правы за то, что делает первый. Что касается 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}}
7 голосов
/ 07 декабря 2011

defaultdict принимает конструктор с нулевым аргументом, который вызывается, когда ключ не найден, как вы правильно объяснили.

lambda: 0, конечно, всегда будет возвращать ноль, но предпочтительный метод для этого - defaultdict(int), который будет делать то же самое.например, создать новый defaultdict(int) или вложенный словарь, если ключ не найден в словаре верхнего уровня.

2 голосов
/ 09 марта 2018

Все ответы достаточно хороши, но я даю ответ, чтобы добавить больше информации:

"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
1 голос
/ 13 января 2015

y = defaultdict(lambda:defaultdict(lambda:0))

будет полезно, если вы попробуете это y['a']['b'] += 1

...