Подтвердить что ты не робот

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, но не мог понять, что именно.

4b9b3361

Ответ 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