Некоторые приемы функционального программирования в Python

    Привет, Хабр!
    В этой статье я хотел бы рассказать о том, что пришло в Python из функциональных языков программирования. Заинтересовавшихся прошу под кат.


    Генераторы списков


    Это легко и просто: вместо


    l = []
    for x in range(10):
        if x % 2 == 0:
            l.append(x)

    мы пишем


    l = [x for x in range(10) if x % 2 == 0]

    Коротко и понятно.


    Как это работает в функциональных языках

    В Haskell тоже самое буде выглядеть так:


    let l = [x | x <- [0..10], x `mod` 2 == 0]

    Лямбды


    Допустим, мы пишем графический интерфейс и у нас есть функция button(**kwargs), где допустимые именованные аргументы: text — для текста, width — для ширины, height — для высоты и command — для callback-функции:


    def callback(event):
        print("Button pressed")
    button(text="Press me", width=32, height=16, command=callback)

    Обратите внимание, насколько маленький у нас callback, неужели его нелзя пропихнуть аргументом? Можно! Нам помогут лямбды:


    button(text="Press me", width=32, height=16, command=lambda x: print("Button pressed"))

    Чисто и легко!


    Как это работает в функциональных языках

    В Haskell передача функции в качестве аргумента встречается на каждом шагу, например функция map берет функцию и список и возвращает список, к каждому элементу которого была применена эта функция:


    map (\x -> x+1) [1..10]

    На Python это:


    map(lambda x: x+1, [x for x in range(1, 10)])

    Правда, в Python нет map.
    upd: map есть!


    Карринг


    Карринг (каррирование) — это когда мы передаем старой функции один или несколько аргументов, чтобы получить новую, которая принимает остальные (спасибо AnutaU за более точное определение). Например: print — это функция (я использую Python 3), у нее есть именованный аргумент end — конец строки, по умолчанию он равен "\n". Я хочу не переходить на новую строку, тогда пишу


    print(str, end="")

    Давайте сделаем функцию printf, которая не будет переходить на новую строку


    def printf(*args, **kwargs):
        kwargs["end"] = ""
        print(*args, **kwargs)

    Коряво, можно и проще:


    from functools import partial
    
    printf = partial(print, end = "")

    Вот он, карринг — мы говорим, что хотим точно такой же, но с перламутровыми пуговицами функцию print, но чтобы end был равен "". Все просто.


    Как это работает в функциональных языках

    И снова Haskell: у нас есть функция +, которая берет два аргумента, мы говорим:


    let plusTwo = (+2)

    теперь у меня есть функция, которая прибавляет 2 к единственному аргументу.


    У меня все, если вы знаете, что еще есть в Python из функциональщины — прошу в комментарии.
    Вопросы и отзывы туда же.

    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 13

      +3
      Правда, в Python нет map.
      Как же это нет?
        –1
        Карринг (каррирование) — это когда мы делаем новую функцию из старой с одним или несколькими аргументами.
        Какое-то не очень понятное определение. Каррированная функция — это функция, которая принимает один аргумент, и возвращает другую функцию, которая принимает остальные.

        Во многих функциональных языках вообще не существует функций нескольких аргументов, они эмулируются либо с помощью каррирования, либо с помощью кортежей.
          0

          Я действительно кривовато объяснил, а насчёт функциональных языков — да так и есть.

          +6
          То что в статье названо каррированием, на самом деле является частичным применением.
            +1
            Третий случай — это частичное применение.
            Каррирование имеет сигнатуру
            curry :: ((a,b)->c)->a->b->c
              +3
              А где filter?map?reduce?functool?
              Если это обзорная статья, то нужно говорить о всех вещах, а не только об очевидном.
              Низачет, в общем то…
                0
                Официальная дока и вот эта милая книжка (мне понравилась). А еще на хабре немного было.
                  0
                  Ваше «чисто и легко» просто не сработает! stackoverflow.com/questions/2970858/why-doesnt-print-work-in-a-lambda
                    0

                    Вот здесь вы не правы: во-первых, я сказал, что использую Python 3, во-вторых, по скобочкам видно, что это функция — т. е. то, что нужно

                      +1
                      да, вы правы — перепутал со вторым питоном :(
                    0

                    Стоит однако отметить что генераторы списков в Python 2 и 3 называются иначе. В Python 2.7 range возвращает массив, а не генератор, а для генератора необходимо вызывать xrange. В третьей версии xrange стал просто range, а выделение готовых массивов происходит через другие механизмы.

                      +1

                      Я же сказал, что использую Python 3

                        –2

                        В статье — только тэг. И никаких деталей

                    Only users with full accounts can post comments. Log in, please.