синтаксис `let` в стиле lisp в списках Python - PullRequest
6 голосов
/ 15 декабря 2009

Рассмотрим следующий код:

>>> colprint([
        (name, versions[name][0].summary or '')
        for name in sorted(versions.keys())
    ])

Этот код выполняет печать элементов словаря versions в порядке возрастания его keys, но поскольку value является другим отсортированным списком, только сводка его first элемент ('max') печатается.

Так как я знаком с let из lisp, я переписал вышеизложенное как:

>>> colprint([
        (name, package.summary or '')
        for name in sorted(versions.keys())
        for package in [versions[name][0]]
    )]

Считаете ли вы, что это нарушает пифонизм ? Можно ли это улучшить?

Примечание: для любопытных colprint определяется здесь .

Ответы [ 5 ]

7 голосов
/ 15 декабря 2009

Почему бы не использовать кортежи?

colprint([(name, version[0].summary or '')
      for (name, version) in sorted(versions.iteritems())])

или даже

colprint(sorted([(name, version[0].summary or '')
             for (name, version) in versions.iteritems()]))

Кроме того, вы можете рассмотреть (в моем первом примере) удаление [] s, потому что таким образом вы получите генератор вместо списка (что может или не может быть полезным, так как я предполагаю, что это напечатает весь массив, поэтому вы не будете сохранять оценки).

5 голосов
/ 16 декабря 2009

В большинстве случаев я не стал бы использовать «хитрый для предложения» (или «эквивалентный»), но я бы использовал, если это естественный способ избежать повторений, особенно дорогостоящих повторений. Э.Г.

xs = [(y, y*1.2, y-3.4) for z in zs for y in [somefun(z)] ]

выглядит намного лучше, чем звонить somefun три раза! -) Так что стоит иметь в виду, даже если, вероятно, не стоит использовать там, где это не убирает повторения.

4 голосов
/ 15 декабря 2009

Таким образом, вы используете «для х в [у]» в качестве замены «пусть х у».

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

1 голос
/ 30 декабря 2009

Как говорит Тордек, вы можете использовать items() или iteritems() в этом случае, чтобы избежать проблемы:

colprint(sorted((name, packages[0].summary or '')
                for (name, packages) in versions.items()))

Перемещение сортировки наружу - приятное прикосновение.

[Обратите внимание, что использование items() немного изменило порядок сортировки - раньше это было по имени с связями, разрешенными в исходном порядке (сортировка Python стабильна), теперь это по имени со связями, разрешенными по сводке. Поскольку первоначальный порядок диктов является случайным, новое поведение, вероятно, лучше.]

Но для других целей (таких как пример Алекса Мартелли), аналог «let» может быть полезен. Я также однажды обнаружил уловку for var in [value], но теперь я нахожу ее уродливой. Более чистой альтернативой может быть «конвейер» пониманий / генераторов, использующий трюк «decorate / undecorate» для передачи добавленной стоимости в кортеж:

# You could write this with keys() or items() - 
# I'm just trying to examplify the pipeline technique.
names_packages = ((name, versions[name][0]) 
                  for name in versions.keys())

names_summaries = ((name, package.summary or '')
                   for (name, package) in names_packages)

colprint(sorted(names_summaries))

Или применимо к примеру Алекса:

ys = (somefun(z) for z in zs)
xs = [(y, y*1.2, y-3.4) for y in ys]

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

См. http://www.dabeaz.com/generators/ для более мощных примеров техники "конвейера" ...

0 голосов
/ 15 декабря 2009

Вы можете переместить сортировку до конца, чтобы избежать некоторых промежуточных списков.

Это выглядит немного лучше, я думаю:

colprint(sorted(
        (name, version[0].summary or '')
        for (name,version) in versions.iteritems())
    ))

Python3 может работать еще лучше:

colprint(sorted(
        (name, first_version.summary or '')
        for (name,(first_version,*_)) in versions.items())
    ))
...