Как стать автором
Обновить

Комментарии 42

Хм, введение в функциональное программирование на Python? Не лучше ли для этой цели использовать функциональные языки, например Scheme? Там и лямбда вычисления лучше продемонстрировать можно, и pattern matching показать. Python все таки не функциональный язык.
Прочитал первую часть и понял почему Python:).
ваш перевод термина list comprehensions совем бессмысленный. варианты с включением, вложением, добавлением и охватом гораздо лучше раскрывают его значение
НЛО прилетело и опубликовало эту надпись здесь
мне больше нравиться вариант «описание списков», чем по сути и является этот «сахарок»
НЛО прилетело и опубликовало эту надпись здесь
собственно, я нигде не предлагал его переводить, но раз уж речь зашла о том, как это звучит на русском, то осмелился предложить свой вариант, который скорее не дословный, а ближе по смыслу. в данном случае, «описание списка» подразумевает наличие спискового/списочного литерала ([ ]) и заключённого в него «описания» элементов списка. соглашаться с моим мнением никого не обязываю)

кстати, генераторы в питоне — это отдельная история, хотя можно согласиться, что выражение в скобках как бы «генерирует» элементы списка

а книга, случайно, не на русском?
НЛО прилетело и опубликовало эту надпись здесь
Не-а, квадратные скобки во втором питоне — это не генератор, это именно сборка или что-то в таком духе.

>>> ( a + b for a, b in (('a', 'b'), ('a', 'b')) )
<generator object at 0xb7bff54c>
>>> [ a + b for a, b in (('a', 'b'), ('a', 'b')) ]
['ab', 'ab']
>>> ( a + b for a, b in (('a', 'b'), ('a', 'b')) )
<generator object at 0xb7bff54c>

ничего себе, век живи век учись. Первый раз такую конструкцию вижу, спасибо.
Если не ошибаюсь, начиная с 2.4 такая возможность есть.
В 3.0 «[...]», насколько знаю, уже будет возвращать настоящие генераторы вместо списков, но пока 3.0 не сильно распространён.
[] — это по сути конструктор списка. В 3.х в этом плане он работает так же как и в 2.х.
Кстати допускается еще такая запись:
>>> def f(a):
...     return a
... 
>>> f(i for i in '123')
<generator object at 0xec7638>

ну а где у меня сказано, что квадратные скобки — это генератор? тем более, что я отдельно упомянул питоновские генераторы. я всего лишь считаю, что list comprehensions — это элемент декларативного программирования в питоне, т.е. это выражение описывает список, его элементы, и пытаюсь это растолковать.
Я и не говорю, что вы ошиблись, наоборот, подтверждаю ваше мнение, что называть «[...]» генератором лучше не стоит во избежание путаницы.
ну да, учитывая, что термин «генератор списков» в оригинальном издании использовался для пояснения, а не в качестве перевода)
НЛО прилетело и опубликовало эту надпись здесь
по-моему, это как раз та ситуация, когда перевод только усугубляет :) Наверное, лучше не переводить вовсе, а использовать «приблизительный» термин — такой как вы придумали, «описание списков», мне кажется вполне нормальным.
НЛО прилетело и опубликовало эту надпись здесь
как я ответил выше, я никому не навязываю такой перевод, но и «генераторы списков» мне тоже не очень нравятся. более того, я не сторонник переводов всего и вся на русский, не смотря на то, что это родной язык, и даже более однозначные термины тоже предпочитаю в оригинальном варианте. вобще, по-моему, стоит оставить этот термин в покое, важнее понимать, что он значит, а не как переводится.
А мне понравилось :) Спасибо, коллега, позволил себе продолжить тему работы со списками при помощи итераторов. Ну и плюс вам, естественно!
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Спасибо за статью.
Но мне интересно, насколько часто используются функциональная парадигма в реальных программах на питоне (а не примерах)? Потому что даже в данной статье сказано, что «в более сложных случаях, лучше использовать функции». И к тому же, я часто слышал упреки в более плохой читаемости кода в случае частого использования map(), reduce(), list comprehension. И у меня, откровенно говоря, складывается впечатление, что в питоне (и именно в питоне) функциональное программирование годится в основном для примеров, или каких-то чисто академических задач.
Интересно, что серьезные программисты на питоне об этом думают?
Внимательнее прочтите последний абзац. Обещают выложить «примеры пожизненнее»
> насколько часто используются функциональная парадигма в реальных программах на питоне (а не примерах)?

Ну, насколько часто используется структурная парадигма в ваших программах? Сколько процентов занимает в них ООП? Нужно понимать, что это тоже инструмент, который можно применять совместно с другими подходами. Вы используете map, filter или reduce? Или list comprehensions? Или генераторы (которые по сути являются continuations)? Если да, то вы уже использовали кусочки того, что мы называем «функциональным подходом».

> в более сложных случаях, лучше использовать функции
недоответил, сорри.

> в более сложных случаях, лучше использовать функции

вы немного неправильно поняли эту фразу. Я имел в виду, что в более сложных случаях лучше использовать функции map, filter и reduce вместо list comprehensions :) Почему — потому что LC имеют свойство «теряться» в синтаксисе; слишком уж незначительны для нашего програмистского взгляда квадратные скобочки.

> И к тому же, я часто слышал упреки в более плохой читаемости кода в случае частого использования map(), reduce()

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

  x = \
    # filter something out
    filter(lambda a: ...,
      # convert something to something else
      map(lambda a: ...,
         # filter other odd things
         filter(someNamedFunction,
            ....
            data_entries)))))


Насколько яснее может выглядеть программа? :) Отступы нам показывают вложенность, последовательность операций читается сразу же, разве нет? Вы начинаете с самой вложенной операции и поднимаетесь вверх — и видите весь алгоритм.
Код можно сделать плохо читаемым и самыми «простыми» средствами, например, вложенными циклами :)

Если применять вышеперечисленные структуры без фанатизма, проблем не возникает и код становиться более компактным. Можно посмотреть стандартные библиотеки, там не так много, но есть. Зато часто используется lambd'ы и замыкания для отложенных вычислений. Соответственно, используются функции высшего порядка.
Пара примеров из реально работающего и используемого в проектах кода. Отправка уведомлений для всем админам в системе:
def notify_admins(msg):
    map(lambda x: x.message_set.create(message=msg),
        User.objects.filter(is_staff=True))


А вот пример поэзотеричнее:
def handle_noargs(self, **kwargs):
        map(unlink, reduce(lambda x,y: x+y, (x for x in [[join(d,f) for f in fs if f.endswith('.pyc') or f.endswith('.pyo')] for d,_,fs in walk('.')] if x)))


Кто первым скажет, то эта функция делает — плюс в карму :-D
Удаляет все файлы с расширением pyc или pyo в текущей директории и всех поддиректориях?
Ага :)
Кстати, я так ни за что бы не написал :-) Читать неудобно, так что раскидал бы на переменные, а вместо map использовал бы цикл.
Ну, я бы тоже так, пожалуй не стал бы писать. Но из песни слов не выкинешь, как говорится. Этот код не моему перу принадлежит — это я из репозитория взял первое, что попалось. Просили же иллюстрацию.
НЛО прилетело и опубликовало эту надпись здесь
Ну говнокод бывает разный: есть былокодерский говнокод, а есть говнокод, написанный просветленным человеком. Говнокод плохо читаем, но первый тип — из-за того, что его автор ваще не втыкает, что пишет, а во втором случае — из-за того, что автор находится на недостижимом для большинства уровне сознания. :-D Я бы эту кодятину отнес, скорее, ко второй категории, но так писать в коммерческих разработках, конечно, не очень хорошо.
Отличная статья, спасибо!
А не будет ли конструкция

reduce(lambda a, b: [ b ] + a, x, [])

слишком «жирной»? При применении редуктора к каждому элементу x всё-таки новый список генерируется… Насколько лучше (и лучше ли) будет вариант с простым циклом?

b=[]
for a in x: b.insert(0, a)
Да, будет гораздо медленней. Этим примером я просто хотел показать, что результат reduce — не обязательно одно значение (т.к. reduce чаще всего применяется именно для свертки списка в одно значение тем или иным способом), но может быть и список, например.

На практике я, конечно, просто сделаю x.reverse()
НЛО прилетело и опубликовало эту надпись здесь
Кстати, использовать LC в случае

map(
lambda a1, a2, a3: a1 + a2 + a3,
[1, 2, 3],
[4, 5, 6],
[7, 8, 9])

тоже можно, если использовать функцию zip

[a1 + a2 + a3 for a1, a2, a3 in zip([1, 2, 3], [4, 5, 6], [7, 8, 9])]
А reduce в 3.0 убрали из встроенных функциях, мотивируя это тем, что его аналог в виде for нагляднее.
Мда. Не могу сказать, что это меня радует. Ну, по крайней мере, его можно вызывать из модуля functools…
В LC присутствует, казалось бы, похожая конструкция:
[ expression(a1, a2) for a1 in x1, for a2 in x2 ]
Но, увы, это не то же самое.


>>> [ a + b for a, b in ('a', 'b'), ('a', 'b') ]
['ab', 'ab']

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации