#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)