Я пытался решить эту маленькую задачу:

Вы хотите defaultdict, который использует другое значение каждый раз, когда ищется несуществующий ключ, то есть счетчик; 1 для первого несуществующего ключа, 2 для второго и т. Д.

Я смог решить это как:

from collections import defaultdict

def f(a=[0]):
    a[0]+=1
    return a[0]

s=defaultdict(f)

Бонус должен был попытаться сделать это в одну строку.

s=defaultdict(lambda a=[0]: (a[0]+=1))

Ошибка синтаксиса: неверный синтаксис _________ ^

Есть ли способ сделать это в лямбде? Обновить изменяемый аргумент по умолчанию и вернуть?

4
bison 1 Май 2019 в 17:23

4 ответа

operator, чтобы спасти:

d = defaultdict(lambda a = [0]: operator.setitem(a, 0, a[0] + 1) or a[0])
3
Sean Vieira 1 Май 2019 в 14:48

Как насчет использования изменяемого типа, такого как список, чтобы отслеживать количество?

s = defaultdict(lambda a=[] : len(a.__iadd__([1])))

Чтобы уменьшить использование памяти:

s = defaultdict(lambda a=[0] : a.__iadd__([a.pop() + 1])[0])
1
Jacques Gaudin 1 Май 2019 в 15:37

Считается ли импорт частью одной строки?

Если нет, вы можете использовать itertools.count

from itertools import count
d = defaultdict(count().__next__)

Если они это сделают, вы можете использовать слегка уродливый взломать

d = defaultdict(__import__('itertools').count().__next__)
2
Holloway 1 Май 2019 в 14:40

Хотя есть много способов решить эту проблему в одной строке, я вижу много вопросов относительно того, можно ли использовать operator.iadd здесь.

Оно не может.

Конечно, появится , что

s = defaultdict(lambda a=[0]: operator.iadd(a[0], 1))

Будет работать, но это не так.

Причина кроется в официальных документах.

Многие операции имеют версию «на месте». Ниже перечислены функции, обеспечивающие более простой доступ к операторам на месте, чем обычный синтаксис; например, оператор x + = y эквивалентен x = operator.iadd (x, y). Другой способ выразить это - сказать, что z = operator.iadd (x, y) эквивалентно составному выражению z = x; z + = y.

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

Для неизменяемых целей, таких как строки, числа и кортежи, обновленное значение вычисляется, но не присваивается обратно входной переменной:

>>> a = 'hello'
>>> iadd(a, ' world')
'hello world'
>>> a
'hello'

Для изменяемых целей, таких как списки и словари, метод на месте выполнит обновление, поэтому последующее присвоение не требуется.

Поскольку объекты int являются неизменяемыми, вы не можете обновить a[0] с помощью iadd.

(Я знаю, что это было сказано в других ответах; я просто подумал, что определенный ответ со ссылкой на документы по Python может быть полезен.)

2
Ray Toal 1 Май 2019 в 14:55