Python defaultdict по умолчанию

#python #lambda #collections #defaultdict

#питон #лямбда — выражение #Коллекции #defaultdict

Вопрос:

Я обнаружил кое-что странное, чего не мог понять. Это тот самый случай:

 from collections import defaultdict
a = defaultdict(lambda: len(a))
 

Это всего лишь часть кода, и код никогда не определял «а» выше.

Вопросы:

  • Можно ли использовать defaultdict как есть, не указывая переменную ранее?
  • Если возможно, в чем смысл этого кода?

Ответ №1:

Возможно, это лучше всего объяснить на примере:

 >>> a = defaultdict(lambda: len(b))
>>> b = 'abcd'
>>> a[0]
4
 

Как вы можете видеть, его можно использовать b в lambda , даже если b он еще не существует на данный момент. Важно то, что b существует во время lambda выполнения. В этот момент Python будет искать переменную с именем b и использовать ее.


Обратите внимание также, что исходный код не обязательно использует длину самого defaultdict . Он просто оценивает все, что a находится в этой точке. Смотрите этот пример:

 >>> a = defaultdict(lambda: len(a))
>>> a['a']
0
>>> a['b']
1
 

Пока все хорошо. Но затем переименуйте некоторые вещи:

 >>> x = a
>>> a = []
>>> x['c']
0
>>> x['d']
0
 

Теперь deaultdict назван x , но он не используется len(x) . Он все еще используется len(a) . Это предостережение может стать важным, если вы отправили defaultdict в функцию, где a это ничего не значит.

Комментарии:

1. Большое спасибо за ваш ответ. В любом случае, но во 2-м блоке, почему a[‘a’]=0?

2. Потому что в тот момент , когда a['a'] оценивается len(a) , все еще 0 . После получения результата выполнения функции lambda ( 0 ) это значение сохраняется в a['a'] файле .

3. О, теперь я понял! Спасибо за вашу большую помощь 🙂

Ответ №2:

вы говорите default dict , когда я пытаюсь что-то сделать с ключом, а он не существует, используйте эту лямбду в качестве начального значения для ключа. поскольку ваш лямбда-код использует a (то есть сам dict), и вы указываете его длину. Это означает, что когда вы выполняете операции с использованием ключа, которого нет в dict, тогда dict будет использовать вместо этого лямбда или, в данном случае, длину dict в качестве значения

 from collections import defaultdict
a = defaultdict(lambda: len(a))

a['one']  = 5 #here dict length is 0 so value is 0   5 = 5
a['two']  = 2 #jere dict length is 1 so value is 1   2 = 3
a['three']  = 1 #here dict length is 2 so value is 2   1 = 3
print(a.items())
print(a['newval']) #here newval doesnt exist so will use default value which is length of dict I.E 3
 

ВЫВОД

 dict_items([('one', 5), ('two', 3), ('three', 3)])
3
 

Комментарии:

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

Ответ №3:

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

 d = dict()
if some_key not in d:
    d[some_key] = list()
d[some_key].append(some_value)
 

defaultdict делает это автоматически для вас, передавая ему вызываемый объект, например, int , list , set , , который будет вызывать int() (значение по умолчанию 0), list() (значение по умолчанию пустой список) и set() (значение по умолчанию пустой набор) соответственно. Ваш lambda также является вызываемым, который возвращает целые числа, поэтому у вас будет dict со значениями int . Но значение, которое вы получаете из выражения, будет зависеть от размера dict .

Вы можете сделать a = defaultdict(lambda: len(a)) ?

Да, вы можете. Лямбда-код не будет выполняться до тех пор, пока не будет вызван, когда он будет искать имя a . Сравните эти два случая.

 f = lambda: len(a)
a = defaultdict(f)
a[0]                  # this is when the lambda is called for the first time
 

Но,

 g = lambda: len(b)
g()                   # this will raise a NameError
b = defauldict(g)