Главная страница
Навигация по странице:

  • Лямбда-функции и функция map

  • УПРАЖНЕНИЕ 2.1 Попробуйте получить те же результаты с помощью спискового включения вместо функции map(). (Решение можно найти в конце главы.)Извлечение окружения вхождений подстрок

  • Сочетание спискового включения и срезов

  • однострочники пайтон. Однострочники Python лаконичный и содержательный код by Кристи. Однострочники


    Скачать 4.44 Mb.
    НазваниеОднострочники
    Анкороднострочники пайтон
    Дата22.04.2022
    Размер4.44 Mb.
    Формат файлаpdf
    Имя файлаОднострочники Python лаконичный и содержательный код by Кристи.pdf
    ТипКнига
    #490720
    страница5 из 21
    1   2   3   4   5   6   7   8   9   ...   21
    49
    Листинг 2.3. Однострочное решение для построчного чтения файла print([line.strip() for line in open("readFile.py")])
    Попробуйте догадаться, какие результаты будут выведены при выполнении этого фрагмента кода, прежде чем читать следующий подраздел.
    Принцип работы
    Для вывода полученного списка в командную оболочку мы применили опе- ратор print()
    . Этот список был создан с помощью спискового включения
    (см. раздел «Поиск самых высокооплачиваемых работников с помощью спискового включения» на с. 42). В части выражение спискового включения используется метод strip()
    строковых объектов.
    Контекст спискового включения проходит в цикле по всем строкам файла.
    В результате выполнения этого однострочника будет выведен просто он сам (поскольку он предназначен для чтения своего файла исходного кода на Python — readFile.py
    ), обернутый в строковый объект и вставленный в список:
    print([line.strip() for line in open("readFile.py")])
    # ['print([line.strip() for line in open("readFile.py")])']
    Этот подраздел демонстрирует, что повышение лаконичности кода делает его более удобочитаемым, не нанося какого-либо ущерба эффективности.
    Лямбда-функции и функция map
    В этом разделе я познакомлю вас с двумя важными возможностями Python: лямбда-функциями и функцией map()
    — ценными инструментами в наборе
    Python-разработчика. Мы воспользуемся ими для поиска конкретного зна- чения в списке строковых значений.
    Общее описание
    Из главы 1 вы узнали, как описать новую функцию с помощью выраже- ния def x
    , за которым следует тело функции. Однако это не единственный способ описания функции в языке Python. Можно также воспользоваться

    50
    Глава 2. Трюки Python
    лямбда-функциями для описания простой функции с возвращаемым значе-
    нием (которое может быть любым объектом, в том числе кортежем, списком или множеством). Другими словами, лямбда-функция обязательно возвра- щает вызывающей стороне значение-объект. Учтите, что на практике это ограничивает сферу применения лямбда-функций, ведь в отличие от обыч- ных функций они не предназначены для выполнения кода без возвращения объекта в вызывающую среду.
    ПРИМЕЧАНИЕ
    Мы уже рассматривали лямбда-функции в главе 1, но поскольку это очень важное понятие, используемое повсеместно в данной книге, мы рассмотрим его подробнее в этом разделе.
    Благодаря лямбда-функциям можно описать новую функцию с помощью одной строки кода, указав ключевое слово lambda
    . Это удобно, если нужно быстро создать функцию для однократного использования и последующе- го немедленного сбора мусора. Посмотрим сначала на точный синтаксис лямбда-функций:
    lambda аргументы : возвращаемое выражение
    Описание такой функции начинается с ключевого слова lambda
    , за ним сле- дует последовательность ее аргументов, которые необходимо будет указать при ее вызове. Далее указывается двоеточие (
    :
    ) и возвращаемое выражение, в котором вычисляется возвращаемое значение на основе аргументов лямб- да-функции. Возвращаемое выражение, в котором вычисляются выводимые функцией результаты, может быть любым выражением Python. В качестве примера рассмотрим следующее описание функции:
    lambda x, y: x + y
    У данной лямбда-функции два аргумента, x
    и y
    . Возвращаемое значение представляет собой просто их сумму, то есть x
    +
    y
    Лямбда-функции обычно задействуют, когда функцию нужно вызвать только один раз и ее можно легко описать с помощью одной строки кода.
    Распространенный пример: использование лямбда-функций с функцией map
    , принимающей в качестве входных аргументов функциональный объ- ект f
    и последовательность s
    . Далее функция map применяет функцию f
    к каждому из элементов последовательности s
    . Конечно, можно описать для

    Лямбда-функции и функция map
    51
    функционального аргумента f
    полноценную поименованную функцию. Но зачастую это снижает удобочитаемость, особенно если функция короткая и понадобится только один раз, так что лучше воспользоваться лямбда- функцией.
    Прежде чем показать вам однострочник, продемонстрирую еще один трюк
    Python, который сильно облегчит вам жизнь: проверку того, включает ли строковое значение x
    подстроку y
    , с помощью выражения y
    in x
    . Этот оператор возвращает
    True при наличии хотя бы одного вхождения строки символов y
    в строке x
    . Например, значение выражения '42'
    in
    'The answer is
    42'
    равно
    True
    , а выражения '21'
    in
    'The answer is
    42'
    равно
    False
    Теперь посмотрим на наш однострочник.
    Код
    Получая на входе список строковых значений, наш следующий однострочник
    (листинг 2.4) создает новый список кортежей, каждый из которых состоит из булева значения и исходной строки. Булево значение указывает, встреча- ется ли в исходном строковом значении строка символов 'anonymous'
    ! Мы назвали полученный в результате список mark
    , поскольку булевы значения
    отмечают (mark) строковые элементы в списке, содержащие строку сим- волов 'anonymous'
    Листинг 2.4. Однострочное решение, помечающее строковые значения, содержащие строку символов 'anonymous'
    ## Данные txt = ['lambda functions are anonymous functions.',
    'anonymous functions dont have a name.',
    'functions are objects in Python.']
    ## Однострочник mark = map(lambda s: (True, s) if 'anonymous' in s else (False, s), txt)
    ## Результаты print(list(mark))
    Какими же будут результаты выполнения этого фрагмента кода?
    Принцип работы
    Функция map()
    добавляет к каждому строковому элементу исходного списка txt булево значение, равное
    True
    , если этот строковый элемент содержит

    52
    Глава 2. Трюки Python слово anonymous. Первый аргумент представляет собой анонимную лямб- да-функцию, а второй — список строковых значений, которые мы хотим проверить на вхождение желаемой подстроки.
    Для поиска подстроки 'anonymous'
    используется возвращаемое выражение лямбда-функции
    (True,
    s)
    if
    'anonymous'
    in s
    else
    (False,
    s)
    . Значение s
    представляет собой входной аргумент лямбда-функции, в этом примере — строковое значение. Если в данной строке встречается последовательность символов 'anonymous'
    , то выражение возвращает кортеж
    (True,
    s)
    . В про- тивном случае возвращается кортеж
    (False,
    s)
    Результат работы этого однострочника выглядит следующим образом:
    ## Результат print(list(mark))
    # [(True, 'lambda functions are anonymous functions.'),
    # (True, 'anonymous functions dont have a name.'),
    # (False, 'functions are objects in Python.')]
    Булевы значения демонстрируют, что только первые два строковых значения в списке содержат подстроку 'anonymous'
    Лямбда-функции очень пригодятся нам в следующих однострочниках. Кро- ме того, вы приблизитесь к достижению своей цели: пониманию всех строк кода Python, которые только встретятся вам на практике.
    УПРАЖНЕНИЕ 2.1
    Попробуйте получить те же результаты с помощью спискового включения вместо функции map()
    . (Решение можно найти в конце главы.)
    Извлечение окружения вхождений подстрок
    с помощью срезов
    В этом разделе вы узнаете о важности понятия среза (slicing) — процесса
    «вырезания» подпоследовательности из исходной полной последователь- ности — для обработки простых текстовых запросов. Мы поищем в каком- нибудь тексте конкретную строку символов, а затем выделим ее из текста вместе с некоторым количеством окружающих ее символов в качестве контекста.

    Извлечение окружения вхождений подстрок с помощью срезов
    53
    Общее описание
    Срезы играют очень важную роль во множестве понятий и навыков, связан- ных с Python, как простых, так и продвинутых, например, при использовании любых встроенных структур данных Python — списков, кортежей и строк.
    Срезы также лежат в основе большого количества продвинутых библиотек
    Python, например NumPy, Pandas, TensorFlow и scikit-learn. Доскональное изучение срезов окажет эффект домино (в положительном смысле) на вашей карьере как Python-разработчика.
    Срезы позволяют извлекать из последовательностей подпоследовательности, например части символьных строк. Синтаксис очевиден. Пусть дана пере- менная x
    , ссылающаяся на строковое значение, список или кортеж. Извлечь из нее подпоследовательность можно с помощью следующей нотации:
    x[начало:конец:шаг]
    Полученная в результате подпоследовательность начинается на индексе
    начало
    (включительно) и заканчивается на индексе
    конец
    (не включая его). При желании можно включить необязательный третий аргумент
    шаг
    , определяющий, какие элементы извлекаются, позволяя выбрать только расположенные через
    шаг
    элементы последовательности. Например, при- менение к переменной x
    =
    'hello world'
    операции среза x[1:4:1]
    дает в ре- зультате строку 'ell'
    . А операция среза x[1:4:2]
    для той же переменной дает строку 'el'
    , поскольку в итоговый срез выбирается только каждый второй элемент. Как вы помните из главы 1, первому элементу последо- вательности любого типа, например, строки или списка, в языке Python соответствует индекс 0.
    Если не включить аргумент
    шаг
    , то Python по умолчанию считает его рав- ным 1. Например, срез x[1:4]
    дает в результате строку 'ell'
    Если опустить аргументы
    начало
    или
    конец
    , то Python предполагает, что вы хотите начать с начала или закончить в конце последовательности. Напри- мер, срез x[:4]
    дает строку 'hell'
    , а срез x[4:]
    — строку 'o world'
    Внимательно посмотрите на следующие примеры, чтобы лучше разобраться в этой функциональности.
    s = 'Eat more fruits!'
    print(s[0:3])

    54
    Глава 2. Трюки Python
    # Eat

    print(s[3:0])
    # (empty string '')
    print(s[:5])
    # Eat m print(s[5:])
    # ore fruits!

    print(s[:100])
    # Eat more fruits!
    print(s[4:8:2])
    # mr

    print(s[::3])
    # E rfi!

    print(s[::-1])
    # !stiurf erom taE
    print(s[6:1:-1])
    # rom t
    Эти варианты простейшего шаблона срезов Python x[начало:конец:шаг]
    демонстрируют множество интересных свойств данной методики:
    если
    начало>=конец
    с положительным значением
    шаг
    , то срез будет пустым ;
    если аргумент
    конец
    больше длины последовательности, то Python вырезает все элементы последовательности вплоть до крайнего справа элемента включительно ;
    если
    шаг
    больше нуля, то по умолчанию
    начало
    среза — крайний слева элемент, а
    конец
    — крайний справа (включительно) ;
    если
    шаг
    меньше нуля, то срез обходит последовательность в обратном порядке. При незаданных аргументах
    начало
    и
    конец
    срез начинается с крайнего справа элемента (включительно) и заканчивается крайним слева элементом (включительно) . Обратите внимание, что если ар- гумент
    конец
    задан, то соответствующая позиция не включается в срез.
    Далее мы воспользуемся срезами и методом string.find(значение)
    для по- иска индекса строкового аргумента
    значение
    в заданной строке.

    Извлечение окружения вхождений подстрок с помощью срезов
    55
    Код
    Наша цель — найти конкретный текст внутри многострочного строкового значения. Затем необходимо вернуть его непосредственное окружение в виде
    18 символов, окружающих найденное вхождение. Извлечение окружения вместе с искомым текстом позволяет увидеть текстовый контекст найденной строки — подобно тому, как Google выводит фрагменты текста, окружающие искомое ключевое слово. В листинге 2.5 мы ищем строку символов 'SQL'
    в письме Amazon к акционерам — вместе с непосредственным ее окружением в виде 18 окружающих строку 'SQL'
    символов.
    Листинг 2.5. Однострочное решение для поиска в тексте последовательностей символов и их непосредственного окружения
    ## Данные letters_amazon = '''
    We spent several years building our own database engine,
    Amazon Aurora, a fully-managed MySQL and PostgreSQL-compatible service with the same or better durability and availability as the commercial engines, but at one-tenth of the cost. We were not surprised when this worked.
    '''
    ## Однострочник find = lambda x, q: x[x.find(q)-18:x.find(q)+18] if q in x else -1
    ## Результат print(find(letters_amazon, 'SQL'))
    Попробуйте догадаться, какими будут результаты выполнения этого фраг- мента кода.
    Принцип работы
    Мы описали лямбда-функцию с двумя аргументами: строковым значением x
    и строкой запроса q
    , которую мы будем искать в тексте. Эту лямбда-функ- цию мы присваиваем переменной с именем find
    . Функция find(x,
    q)
    ищет строку запроса q
    в строке текста x
    Если поисковый запрос q
    не встречается в строковом значении x
    , мы возвра- щаем результат
    –1
    . В противном случае вырезаем из строки текста первое вхождение поискового запроса плюс 18 символов слева и 18 символов справа в качестве окружения запроса. Индекс первого вхождения q
    в x
    мы

    56
    Глава 2. Трюки Python находим с помощью строковой функции x.find(q)
    , которую вызываем дважды: чтобы определить индекс начала и индекс конца среза, но оба вызова возвращают одно значение, поскольку ни запрос q
    , ни строковое значение x
    не меняются.
    И хотя этот код прекрасно работает, избыточный вызов функции требует дополнительных вычислительных ресурсов — недостаток, который можно легко исправить, прибегнув к добавлению вспомогательной переменной для хранения результата первого вызова этой функции и обращению к значению данной переменной в дальнейшем в целях повторного использования этого результата.
    Это обсуждение проливает свет на немаловажный компромисс: ограничивая себя одной строкой кода, мы лишаемся возможности описать и повторно использовать вспомогательную переменную для хранения индекса первого вхождения поискового запроса. Вместо этого нам приходится выполнять одну и ту же функцию find для вычисления индекса начала среза (и умень- шить результат на 18 позиций индекса) и индекса конца среза (и увеличить результат на 18 позиций индекса). В главе 5 я расскажу вам о более эффек- тивном способе поиска паттернов в строках текста (с помощью регулярных выражений), позволяющем решить эту проблему.
    При поиске строки символов 'SQL'
    в письме Amazon к акционерам мы на- ходим следующее вхождение поискового запроса в тексте:
    ## Результат print(find(letters_amazon, 'SQL'))
    # a fully-managed MySQL and PostgreSQL
    В результате получаем искомую строку символов и несколько слов около нее в качестве контекста. Срезы — важнейший элемент базового образова- ния разработчика на языке Python. Давайте рассмотрим еще один пример однострочника.
    Сочетание спискового включения и срезов
    В этом разделе мы воспользуемся сочетанием спискового включения и сре- зов для выборки из двумерного набора данных. Наша цель — создать меньшую, но вполне репрезентативную выборку данных из неприемлемо большого набора данных.

    Сочетание спискового включения и срезов
    57
    Общее описание
    Представьте, что работаете финансовым аналитиком в крупном банке и обу- чаете новую модель машинного обучения, предназначенную для прогнозов курсов акций. Однако набор данных огромен, и обучение модели занимает на вашем компьютере буквально вечность. Например, в машинном обуче- нии часто контролируется точность предсказания модели для различных наборов ее параметров. В нашем приложении, скажем, приходится ждать часами завершения обучения модели (обучение очень сложных моделей на больших объемах данных на самом деле занимает часы). Для ускорения мы сократим набор данных вдвое, исключив из него каждую вторую точку данных курсов акций. Вряд ли эта модификация существенно снизит без- ошибочность модели.
    В данном разделе мы обратимся к двум возможностям Python, о которых вы узнали ранее в этой главе: списковое включение и срезы. Списковое включение позволяет проходить в цикле по всем элементам списка, после- довательно модифицируя их. Срезы помогают быстро выбрать из заданного списка каждый второй элемент, а потому прекрасно подходят для простых операций фильтрации. Посмотрим внимательнее на совместное использо- вание этих двух возможностей.
    Код
    Наша цель — создать на основе имеющихся данных новую обучающую вы- борку: список списков, каждый из которых состоит из шести чисел с плава- ющей точкой. Для этого выберем из исходного набора данных каждое второе значение с плавающей точкой. Взгляните на листинг 2.6.
    Листинг 2.6. Однострочное решение для выборки данных
    ## Данные (ежедневные котировки акций ($))
    price = [[9.9, 9.8, 9.8, 9.4, 9.5, 9.7],
    [9.5, 9.4, 9.4, 9.3, 9.2, 9.1],
    [8.4, 7.9, 7.9, 8.1, 8.0, 8.0],
    [7.1, 5.9, 4.8, 4.8, 4.7, 3.9]]
    ## Однострочник sample = [line[::2] for line in price]
    ## Результат print(sample)

    58
    Глава 2. Трюки Python
    Как обычно, посмотрим, сможете ли вы догадаться, какими будут результаты выполнения этого фрагмента кода.
    Принцип работы
    В нашем решении используется двухэтапный подход. Во-первых, мы вос- пользуемся списковым включением для прохода в цикле по всем строкам исходного списка, price
    . Во-вторых, создадим новый список значений с плавающей точкой путем среза каждой из строк; для этого мы доба- вим line[начало:конец:шаг]
    с параметрами
    начало
    и
    конец
    по умолчанию и
    шаг
    =
    2
    . Этот новый список чисел с плавающей точкой состоит всего из трех значений с плавающей точкой (вместо шести), в результате чего полу- чается следующий массив:
    ## Результат print(sample)
    # [[9.9, 9.8, 9.5], [9.5, 9.4, 9.2], [8.4, 7.9, 8.0], [7.1, 4.8, 4.7]]
    Это простой однострочник, использующий встроенную функциональность
    Python. Однако в главе 3 вы увидите еще более короткую версию, в которой для исследования данных применяется библиотека NumPy.
    1   2   3   4   5   6   7   8   9   ...   21


    написать администратору сайта