Разница между defaultdict(lambda:None) и defaultdict(int)

Что именно делает ТИП lambda при использовании с defaultdict? У меня есть этот пример, и он отлично работает даже для int, list и lambda в качестве аргумента:

d = defaultdict(int)
d['one'] = lambda x:x*x
d['one'](2)
4

d = defaultdict(list)
d['one'] = lambda x:x*x
d['one'](2)
4

d = defaultdict(lambda: None)
d['one'] = lambda x:x*x
d['one'](2)
4

У меня каждый раз один и тот же результат. Итак, какова основная причина инициализации лямбда «по умолчанию (lambda: None)»? Похоже, словарь defaultdict не заботится о том, какой ТИП аргумента передается.


person rva    schedule 22.11.2015    source источник
comment
Вы можете получить ответ на него по следующей ссылке stackoverflow.com/a/49184504/7187965   -  person Prashant Pathak    schedule 09.03.2018


Ответы (2)


Ваш пример имеет смысл только тогда, когда вы получаете доступ к ключам, которые явно не добавлены в словарь:

>>> d = defaultdict(int)
>>> d['one']
0
>>> d = defaultdict(list)
>>> d['one']
[]
>>> d = defaultdict(lambda: None)
>>> d['one'] is None
True

Как видите, использование словаря по умолчанию даст каждому ключу, который вы пытаетесь получить доступ, значение по умолчанию. Это значение по умолчанию берется путем вызова функции, которую вы передаете конструктору. Таким образом, передача int установит int() в качестве значения по умолчанию (которое равно 0); передача list установит list() в качестве значения по умолчанию (это пустой список []); и передача lambda: None установит (lambda: None)() в качестве значения по умолчанию (то есть None).

Это то, что делает словарь по умолчанию. Ничего больше.

Идея состоит в том, что таким образом вы можете установить значения по умолчанию, которые вам не нужно настраивать вручную при первом доступе к ключу. Так, например, что-то вроде этого:

d = {}
for item in some_source_for_items:
    if item['key'] not in d:
        d[item['key']] = []

    d[item['key']].append(item)

который просто устанавливает новый пустой список для каждого элемента словаря при доступе к нему, может быть сведен к следующему:

d = defaultdict(list)
for item in some_source_for_items:
    d[item['key']].append(item)

И defaultdict позаботится о правильной инициализации списка.

person poke    schedule 22.11.2015

Вы не используете фабрику значений по умолчанию. Вы не увидите разницы, если все, что вы делаете, это назначаете ключи, а не пытаетесь получить ключ, которого еще нет в словаре.

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

>>> from collections import defaultdict
>>> def demo_factory():
...     print('Called the factory for a missing key')
...     return 'Default value'
...
>>> d = defaultdict(demo_factory)
>>> list(d)  # list the keys
[]
>>> d['foo']
Called the factory for a missing key
'Default value'
>>> list(d)
['foo']
>>> d['foo']
'Default value'
>>> d['bar'] = 'spam'  # assignment is not the same thing
>>> list(d)
['foo', 'bar']
>>> d['bar']
'spam'    

Только в первый раз, когда я попытался получить доступ к ключу 'foo', была вызвана фабрика для создания значения по умолчанию, которое затем сохраняется в словаре для доступа в будущем.

Таким образом, для каждого из ваших разных примеров различается то, какое значение по умолчанию будет создано для каждого из них. Вы никогда не получите доступ к этой функции, потому что вы напрямую назначены клавише 'one'.

Если бы вы обратились к несуществующему ключу, вы бы создали целое число со значением 0, пустой список или None соответственно.

person Martijn Pieters    schedule 22.11.2015