List comprehension — приятная штука, позволяющая во многих ситуациях выразить мысль не только коротко, но и понятно. И всё же иногда кажется, что там чего-то не хватает. Вот несколько вариантов записи одного выражения:
[target for target in [long_expr_of(source) for source in sources]
if test_expr_of(target)]
filter(lambda x: test_expr_of(x),
[long_expr_of(source) for source in sources])
[long_expr_of(source) for source in sources
if test_expr_of(long_expr_of(source))]
Первый способ громоздок, да и читаются вложенные списки не так хорошо. Второй способ выглядит неплохо, только если есть готовая функция test_expr_of и нет необходимости писать lambda-выражение. Третий способ неприятен с точки зрения эффективности. В таких случаях я предпочитаю разбивать вычисление на два выражения:
targets = [long_expr_of(source) for source in sources]
targets = [target for target in targets if test_expr_of(target)]
Вроде всё замечательно и ничего больше не нужно. И всё-таки, вспоминая SQL, хочется записать что-то вроде:
[long_expr_of(source) as target for source in sources
if test_expr_of(target)]
Выглядит очень приятно. Может стоит написать PEP?
6 комментариев:
Хмм... Ну не знаю, первый вариант (или последний) был бы нормальный, только вложенный lisp comprehension надо бы заменить на генераторное выражение. ;)
Ну от использования generator comprehension вместо list comprehension суть вопроса не меняется. Вероятно, ради такой мелочи вряд ли стоит дополнительно замусоривать язык.
Ум, забыл подписаться на комментарии.
Я даже не знаю, если б такую штуку можно было еще где-то использовать... Впрочем, я часто отказываюсь от LC/GE именно из-за этого прикола. ;) Так что может и проканает. :)
Я делаю так.
> [long_expr_of(source) for source in sources if test_expr_of(long_expr_of(source))]
filter(test_expr_of, map(long_expr_of, sources))
Вообще я как-то стал больше склоняться к использованию map/reduce/filter. Совместно с operator и curry.
Зацените:
set(reduce(
__operator.iadd,
__map(operator.attrgetter('parsers'), sources),
__[]))
И это далеко не всё :-).
..bw
Я имел ввиду, что test_expr_of и long_expr_of являются выражениями (отсюда expr в названиях), то есть в map-reduce их придётся записывать через lambda. Согласитесь, читать код с вызовами map/reduce и громоздкими выражениями в lambda уже не так приятно.
Теперь понятно. Да, лямбда далеко не везде смотрится на своем месте.
В зависимости от размера и мудрености выражения его бы следовало вынести наружу и дать "человеческое" имя, а дальше использовать как угодно.
..bw
Отправить комментарий