Альтернативы использованию оператора моржа:= внутри вложенного понимания

Скажем, для демонстрации я должен взять список "входных точек" и вывести три пары чисел, начинающиеся с этих точек:

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

Другие вопросы по тегам