Альтернативы использованию оператора моржа:= внутри вложенного понимания
Скажем, для демонстрации я должен взять список "входных точек" и вывести три пары чисел, начинающиеся с этих точек:
1 -> [(1, 2), (3, 4), (5, 6)]
12 -> [(12, 13), (14, 15), (16, 17)]
...
Я мог бы сделать это в расширенном цикле for:
points = [1, 12, 42, 69] # arbitrary inputs
result = []
for point in points:
rng = range(points, points + 6)
pairs = list(zip(rng[::2], rng[1::2]))
result.append(pairs)
return result
Я также могу сделать это более кратко с пониманием списка, используя оператор моржа, чтобы избежать вызова range()
вновь и вновь:
points = [1, 12, 42, 69]
result = [
list(zip((y := range(p, p + 6))[::2], y[1::2]))
for p in startpoints
]
Но если бы я хотел, скажем, использовать понимание списка вместо list()
, и далее обрабатывать результаты zip()
(например, получить мои выходные данные в виде строк), я не могу этого сделать:
points = [1, 12, 42, 69]
result = [
[
str(tup)
for tup in zip((y := range(p, p + 6))[::2], y[1::2])
]
for p in startpoints
]
# produces the following error:
File "<stdin>", line 4
SyntaxError: assignment expression cannot be used in a comprehension iterable expression
PEP 572 упоминает, что проблемы с реализацией оператора присваивания лежат в основе этого:
Из-за проектных ограничений в эталонной реализации (анализатор таблицы символов не может легко обнаружить, когда имена повторно используются между крайним левым итерируемым выражением понимания и остальной частью понимания), именованные выражения полностью запрещены как часть итерабельных выражений понимания (часть после каждого ключевого слова "in" и перед любым последующим ключевым словом "if" или "for")
что меня разочаровывает. Есть ли какие-либо обходные пути, кроме расширения его до полнойfor
петля?
0 ответов
Классический способ сделать это:
[
[tup for y in [range(p, p + 6)] for tup in zip(y[::2], y[1::2])]
for p in points
]
Однако это довольно уродливо (и требует создания дополнительного списка / кортежа для каждого p).
Вы можете просто избежать всего диапазона /zip с помощью:
[[(y, y + 1) for y in range(p, p + 6, 2)] for p in points]
Я считаю, что это делает его более читаемым (а также немного быстрее, потому что он позволяет избежать zip и вызовов 2 из 3 диапазонов для каждого p).