Используйте случай для вложенных / множественных списков или выражений генератора. Когда он более изящный?

Иногда я вижу подобное:

(k for k in (j for j in (i for i in xrange(10)))) 

Теперь это действительно сгибает мой мозг, и я предпочел бы, чтобы он не был представлен таким образом.

Существуют ли какие-либо варианты использования или примеры использования этих вложенных выражений, где он был более изящным и читаемым, чем если бы он был вложенным циклом?

Изменить: Спасибо за примеры способов упрощения этого. На самом деле это не то, о чем я просил, мне было интересно, были ли времена, когда они были изящны.

    7 Solutions collect form web for “Используйте случай для вложенных / множественных списков или выражений генератора. Когда он более изящный?”

    Проверьте PEP 202, в котором был введен синтаксис понятий списка.

    Для понимания вашего примера из самого Guido существует простое правило:

    • Форма [… для x … для y …] гнездится, причем последний индекс отличается самым быстрым, точно так же, как вложенные для циклов.

    Также из PEP 202, который отвечает на ваш вопрос:

     обоснование
         Учет списков обеспечивает более сжатый способ создания списков в
         ситуации, когда map () и filter () и / или вложенные петли
         в настоящее время используется.
    

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

    Если вы беспокоитесь о слишком большой сложности на одной линии, вы можете разбить ее:

     (k for k in (j for j in (i for i in xrange(10)))) 

    Я всегда находил продолжение строк, чтобы выглядеть немного странным в Python, но это облегчает просмотр того, что происходит в каждом из них. Поскольку дополнительное задание / поиск не собирается ничего делать или что-либо сломать, вы также можете написать его следующим образом:

     gen1 = (i for i in xrange(10)) gen2 = (j for j in gen1) gen3 = (k for k in gen2) 

    На практике я не думаю, что я когда-либо вложил понимание более чем в 2 глубины, и в этот момент все еще было довольно легко понять.

    В случае вашего примера я, вероятно, напишу его как:

     foos = (i for i in xrange(10)) bars = (j for j in foos) bazs = (k for k in bars) 

    Учитывая более описательные имена, я думаю, что это, вероятно, будет совершенно ясным, и я не могу себе представить, что есть какая-то измеримая разница в производительности.

    Возможно, вы думаете больше о выражениях:

     (x for x in xs for xs in ys for ys in lst) 

    – на самом деле, это даже не актуально. Вы должны положить вещи в другом порядке:

     (x for ys in lst for xs in ys for x in xs) 

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

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

     irange = (i for i in xrange(10)) jrange = (j for j in irange) krange = (k for k in jrange) 

    Неважно, что вы выбираете, я думаю, что многострочный пример более читабельен, в общем.

    Предостережение: элегантность отчасти зависит от вкуса.

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

    То, что понимает список, кратким – они позволяют вам делать что-то в одной строке.

    Время использовать понимание списка – это когда вам нужен определенный список, он может быть создан на лету довольно легко, и вам не нужны или нужны промежуточные объекты. Это может произойти, когда вам нужно упаковать некоторые объекты в текущую область действия в один объект, который вы можете использовать в функции, например, ниже:

     list1 = ['foo', 'bar'] list2 = ['-ness', '-ity'] return filterRealWords([str1+str2 for str1 in list1 for str2 in list2]) 

    Этот код примерно такой же читабельный, как и расширенная версия, но он намного короче. Он избегает создания / именования объекта, который используется только один раз в текущей области, что, возможно, более элегантно.

    Выражение:

     (k for k in (j for j in (i for i in xrange(10)))) 

    эквивалентно:

     (i for i in xrange(10)) 

    это почти то же самое:

     xrange(10) 

    Последний вариант более элегантный, чем первый.

    Я считаю, что это может быть полезно и элегантно в таких ситуациях, когда у вас есть такой код:

     output = [] for item in list: if item >= 1: new = item += 1 output.append(new) 

    Вы можете сделать это одним слоем следующим образом:

     output = [item += 1 for item in list if item >= 1] 
    Python - лучший язык программирования в мире.