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

  • Исправление испорченных списков с помощью присваивания срезам

  • corrupted

  • Firefox

  • Анализ данных о сердечной деятельности с помощью конкатенации списков

  • Поиск компаний, платящих меньше минимальной зарплаты, с помощью выражений-генераторов

  • Форматирование баз данных с помощью функции zip()

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


    Скачать 4.44 Mb.
    НазваниеОднострочники
    Анкороднострочники пайтон
    Дата22.04.2022
    Размер4.44 Mb.
    Формат файлаpdf
    Имя файлаОднострочники Python лаконичный и содержательный код by Кристи.pdf
    ТипКнига
    #490720
    страница6 из 21
    1   2   3   4   5   6   7   8   9   ...   21
    УПРАЖНЕНИЕ 2.2
    Вернитесь к этому однострочнику после изучения главы 3 и попробуйте написать его более лаконичный вариант с помощью возможностей библио- теки NumPy. Подсказка: воспользуйтесь расширенными возможностями срезов NumPy.
    Исправление испорченных списков с помощью
    присваивания срезам
    В этом разделе вы познакомитесь с замечательной возможностью Python: присваиванием срезам. В процессе присваивания срезам с левой стороны используется нотация среза для модификации подпоследовательности ис- ходной последовательности.

    Исправление испорченных списков с помощью присваивания срезам
    59
    Общее описание
    Представьте, что работаете в маленьком интернет-стартапе, отслеживающем, какие браузеры встречаются у его пользователей (Google Chrome, Firefox,
    Safari). Данные хранятся в БД. Для их анализа вы загружаете собранные данные о браузерах в большой список строковых значений, но из-за ошибки в алгоритме отслеживания каждая вторая строка ошибочна и требует замены на правильную.
    Пусть ваш веб-сервер всегда перенаправляет первый веб-запрос поль- зователя на другой URL (распространенная практика в веб-разработке, известная под кодом HTML 301: перемещено навсегда). Из этого мы дела- ем вывод, что первое значение для браузера будет равно второму в боль- шинстве случаев, поскольку при ожидании перенаправления браузер пользователя не меняется. Это означает, что можно легко восстановить исходные данные. Фактически нам нужно дублировать каждое второе строковое значение в списке, то есть превратить список
    ['Firefox',
    'corrupted',
    'Chrome',
    'corrupted']
    в список
    ['Firefox',
    'Firefox',
    'Chrome',
    'Chrome']
    Как сделать это быстро, удобочитаемо и эффективно (желательно в одной строке кода)? Сначала в голову приходит идея создать новый список, пройти в цикле по поврежденному списку и добавить каждое из неис- порченных значений для браузеров в новый список дважды. Но это тре- бует двух списков в коде, каждый из которых может включать миллионы записей. Кроме того, данное решение требует нескольких строк кода, а значит, отрицательно скажется на лаконичности и удобочитаемости исходного кода.
    К счастью, вы только что узнали о замечательной возможности Python: при- сваивании срезам. Оно позволяет выбирать и заменять последовательности
    элементов, расположенных между индексами i
    и j
    , с помощью нотации сре- зов вида lst[i:j]
    =
    [0 0
    ...0]
    . Благодаря тому что срез lst[i:j]
    стоит с левой
    стороны операции присваивания (а не с правой, как мы видели раньше), эта возможность и называется присваиванием срезам.
    Идея присваивания срезу проста и состоит в замене всех выбранных эле- ментов исходной последовательности слева элементами справа.

    60
    Глава 2. Трюки Python
    Код
    Наша цель — заменить каждое второе строковое значение на непосредствен- но предшествующее ему (листинг 2.7).
    Листинг 2.7. Однострочное решение для замены всех испорченных строк
    ## Данные visitors = ['Firefox', 'corrupted', 'Chrome', 'corrupted',
    'Safari', 'corrupted', 'Safari', 'corrupted',
    'Chrome', 'corrupted', 'Firefox', 'corrupted']
    ## Однострочник visitors[1::2] = visitors[::2]
    ## Результат print(visitors)
    Какова же будет исправленная последовательность браузеров в результате выполнения этого кода?
    Принцип работы
    Наше однострочное решение заменяет «испорченные» строковые значения на строки с браузерами, которые предшествуют им в списке. Для доступа к испорченным элементам в списке visitors используется нотация присваи- вания срезам. Я выделил выбранные элементы в следующем фрагменте кода:
    visitors = ['Firefox', 'corrupted', 'Chrome', 'corrupted',
    'Safari', 'corrupted', 'Safari', 'corrupted',
    'Chrome', 'corrupted', 'Firefox', 'corrupted']
    Наш код заменяет эти выделенные элементы срезом справа от операции присваивания. Они выделены в следующем фрагменте кода:
    visitors = ['Firefox', 'corrupted', 'Chrome', 'corrupted',
    'Safari', 'corrupted', 'Safari', 'corrupted',
    'Chrome', 'corrupted', 'Firefox', 'corrupted']
    Элементы из первого указанного набора заменяются элементами из второго.
    Таким образом, итоговый список visitors выглядит так (жирным шрифтом выделены замененные элементы):
    ## Результат print(visitors)
    '''

    Анализ данных о сердечной деятельности с помощью конкатенации списков
    61
    ['Firefox', 'Firefox', 'Chrome', 'Chrome',
    'Safari', 'Safari', 'Safari', 'Safari',
    'Chrome', 'Chrome', 'Firefox', 'Firefox']
    '''
    Результат представляет собой исходный список, в котором все строковые значения 'corrupted'
    заменены предшествующими им строковыми значе- ниями с указанием браузера. Таким образом, мы исправляем испорченный набор данных.
    Присваивания срезам — простейший и наиболее эффективный способ решения нашей маленькой задачи. Обратите внимание, что статистика использования браузеров в очищенных данных неискаженная: браузер с долей на рынке 70 % в испорченных данных сохранит долю на рынке 70 % и в очищенных данных. Очищенные данные можно затем применять для дальнейшего анализа — например, чтобы узнать, лучшие ли покупатели пользователи Safari (в конце концов, они обычно тратят больше денег на аппаратное обеспечение).
    Итак, вы освоили простую и лаконичную методику модификации списков программным образом, причем без создания дополнительных объектов.
    Анализ данных о сердечной деятельности
    с помощью конкатенации списков
    В этом разделе вы узнаете, как с помощью конкатенации списков много- кратно копировать маленькие списки и объединить их в один большой для генерации циклических данных.
    Общее описание
    На сей раз мы работаем над маленьким программным проектом для боль- ницы. Наша задача — мониторинг и визуализация статистики состояния здоровья пациентов путем отслеживания их сердечных циклов. Благодаря построению графиков данных сердечных циклов мы помогаем докторам и пациентам отслеживать возможные отклонения от этого цикла. Например, при заданном ряде измерений отдельного сердечного цикла, хранящихся в списке
    [62,
    60,
    62,
    64,
    68,
    77,
    80,
    76,
    71,
    66,
    61,
    60,
    62]
    , необходимо получить визуализацию, подобную изображенной на рис. 2.2.

    62
    Глава 2. Трюки Python
    Рис. 2.2. Визуализация ожидаемых сердечных циклов путем копирования избранных значений из списка измеренных данных
    Проблема состоит в том, что первое и второе значения данных в нашем списке избыточны:
    [62,
    60,
    62,
    64,
    68,
    77,
    80,
    76,
    71,
    66,
    61,
    60,
    62]
    . Это удобно при построении графика одного сердечного цикла в качестве указа- ния на то, что был визуализирован один полный цикл. Однако необходимо избавиться от этих избыточных данных, чтобы наши ожидаемые сердечные циклы не выглядели так, как на рис. 2.3, при копировании одного и того же сердечного цикла.
    Ясно, что нужно очистить исходный список, удалив из него избыточные два первых и два последних значения данных, то есть список
    [62,
    60,
    62,
    64,
    68,
    77,
    80,
    76,
    71,
    66,
    61,
    60,
    62]
    превращается в
    [60,
    62,
    64,
    68,
    77,
    80,
    76,
    71,
    66,
    61]
    Можно воспользоваться срезами в сочетании с новой возможностью
    Python — конкатенацией списков (list concatenation), создающей новый список путем конкатенации (то есть соединения) существующих списков.
    Например, операция
    [1,
    2,
    3]
    +
    [4,
    5]
    создает новый список
    [1,
    2,
    3,
    4,
    5]
    , не заменяя при этом существующие. При этом можно выполнить операцию
    *
    для многократной конкатенации одного и того же списка: например, опера- ция
    [1,
    2,
    3]
    *
    3
    создает новый список
    [1,
    2,
    3,
    1,
    2,
    3,
    1,
    2,
    3]
    Кроме того, можно использовать модуль matplotlib.pyplot для построения графика сгенерированных данных о сердечной деятельности. Функция

    Анализ данных о сердечной деятельности с помощью конкатенации списков
    63
    Рис. 2.3. Визуализация ожидаемых сердечных циклов путем копирования всех значений из списка измеренных данных (без фильтрации избыточных данных)
    plot(data)
    библиотеки matplotlib ожидает на входе итерируемый аргумент data
    (итерируемый означает просто объект, по которому можно проходить в цикле, например список) и использует его в качестве значений y
    для по- следующих типов данных на двумерном графике. Рассмотрим этот пример подробнее.
    Код
    У нас есть список целых чисел, отражающий измерения сердечного цикла.
    Сначала мы хотим очистить данные, удалив два первых и два последних значения из этого списка. Далее создаем новый список с ожидаемыми будущими значениями частоты сердечных сокращений, копируя сердеч- ный цикл в экземпляры для будущего времени. Код приведен в листин- ге 2.8.
    Листинг 2.8. Однострочное решение для предсказания частоты сердечных сокращений в различные моменты времени
    # Зависимости import matplotlib.pyplot as plt
    ## Данные cardiac_cycle = [62, 60, 62, 64, 68, 77, 80, 76, 71, 66, 61, 60, 62]

    64
    Глава 2. Трюки Python
    ## Однострочник expected_cycles = cardiac_cycle[1:-2] * 10
    ## Результат plt.plot(expected_cycles)
    plt.show()
    Далее вы узнаете результаты выполнения этого фрагмента кода.
    Принцип работы
    Приведенный однострочник работает в два этапа. Во-первых, мы очищаем данные с помощью среза с отрицательным аргументом конца, равным
    –2
    , что- бы срез включал в себя все элементы до правого конца, за исключением двух последних избыточных значений. Во-вторых, мы выполняем конкатенацию полученных значений данных десять раз с помощью оператора повтора
    *
    В результате получаем список из 10
    × 10 = 100 целых чисел, состоящих из конкатенаций данных о сердечной деятельности. И на построенном графике результата мы видим желаемую картину, показанную ранее на рис. 2.2.
    Поиск компаний, платящих меньше
    минимальной зарплаты, с помощью
    выражений-генераторов
    В этом разделе вас ожидает комбинация некоторых уже изученных базовых возможностей Python, а также знакомство с удобной функцией any()
    Общее описание
    Представьте, что работаете в инспекции Министерства труда США и хотите найти компании, которые платят меньше минимальной почасовой ставки, чтобы инициировать расследование. Подобно голодным псам у дверцы грузовика с мясом, ваши офицеры, следящие за соблюдением Закона о спра- ведливых условиях труда (Fair Labor Standards Act, FLSA), ждут список компаний, нарушающих закон о минимальной зарплате. Можете ли вы предоставить им такой список?
    Вот инструмент, который вам стоит взять на вооружение: функция any()
    языка Python, принимающая на входе итерируемый объект, например

    Поиск компаний, платящих меньше минимальной зарплаты
    65
    список, и возвращающая
    True
    , если вычисление хотя бы одного элемента этого итерируемого объекта дает
    True
    . Например, выражение any([True,
    False,
    False,
    False])
    равно
    True
    , а выражение any([2<1,
    3+2>5+5,
    3–2<0,
    0])
    равно
    False
    ПРИМЕЧАНИЕ
    Создатель языка Python Гвидо ван Россум (Guido van Rossum), боль- шой поклонник функции any(), даже предложил включить ее в качестве встроенной функции в Python 3. См. подробности в его сообщении в бло- ге от 2005 года, The Fate of reduce() in Python 3000 (
    «Судьба функции reduce() в Python 3000
    »): https://www.artima.com/weblogs/viewpost.jsp? thread=98196.
    Интересное расширение Python, обобщающее списковые включения, — вы-
    ражения-генераторы. Они работают совершенно аналогично списковым включениям, только без создания в памяти собственно списка. Числа соз- даются по ходу дела, без сохранения их явным образом в списке. Например, вместо вычисления квадратов первых 20 натуральных чисел с помощью спи- скового включения, sum([x*x for x
    in range(20)])
    , можно воспользоваться выражением-генератором: sum(x*x for x
    in range(20))
    Код
    Наши данные представляют собой ассоциативный массив ассоциативных массивов, в которых хранятся почасовые ставки работников компаний. Не- обходимо выделить из него список компаний, платящих по крайней мере одному сотруднику меньше установленной законом минимальной почасовой ставки (
    <
    $9
    ) (листинг 2.9).
    Листинг 2.9. Однострочное решение для поиска компаний, платящих меньше установленной законом минимальной почасовой ставки
    ## Данные companies = {
    'CoolCompany' : {'Alice' : 33, 'Bob' : 28, 'Frank' : 29},
    'CheapCompany' : {'Ann' : 4, 'Lee' : 9, 'Chrisi' : 7},
    'SosoCompany' : {'Esther' : 38, 'Cole' : 8, 'Paris' : 18}}
    ## Однострочник illegal = [x for x in companies if any(y<9 for y in companies[x].values())]

    66
    Глава 2. Трюки Python
    ## Результат print(illegal)
    Деятельность каких компаний необходимо расследовать более подробно?
    Принцип работы
    В этом однострочнике используются два выражения-генератора.
    Первое выражение, y<9
    for y
    in companies[x].values()
    , генерирует входные данные для функции any()
    . Для каждого сотрудника оно проверяет, не платят ли ему по почасовой ставке ниже минимальной, y<9
    . Результат представляет собой итерируемый объект значений булева типа. Метод values()
    ассоциа- тивного массива возвращает хранящуюся в нем коллекцию значений. Напри- мер, выражение companies['CoolCompany'].values()
    возвращает коллекцию почасовых ставок dict_values([33,
    28,
    29])
    . Если хотя бы одна из них ниже минимальной, то функция any()
    вернет
    True
    , а название компании будет сохра- нено в виде строкового значения в итоговом списке illegal
    , как описано ниже.
    Второе выражение-генератор представляет собой списковое включение
    [x for x
    in companies if any(...)]
    и создает список названий компаний, для которых предыдущий вызов функции any()
    возвращает
    True
    . Это и есть компании, пла- тящие своим сотрудникам меньше минимальной почасовой ставки. Обратите внимание, что выражение x
    in companies обходит все ключи ассоциативного массива: названия компаний 'CoolCompany'
    ,
    'CheapCompany'
    и 'SosoCompany'
    Результат, соответственно, будет выглядеть следующим образом:
    ## Результат print(illegal)
    # ['CheapCompany', 'SosoCompany']
    В двух из трех компаний нужно провести дальнейшее расследование, по- скольку они платят слишком мало по крайней мере одному сотруднику.
    Похоже, вашим офицерам стоит поговорить с Энн, Криси и Коулом!
    Форматирование баз данных с помощью
    функции zip()
    В этом разделе вы узнаете, как задать названия столбцов базы данных для списка строк с помощью функции zip()

    Форматирование баз данных с помощью функции zi p()
    67
    Общее описание
    Функция zip()
    принимает на входе итерируемые объекты iter_1
    , iter_2
    ,
    , iter_n и агрегирует их в один итерируемый объект путем выстраива- ния соответствующих i-х значений в один кортеж. В результате получается
    итерируемый объект из кортежей. Например, рассмотрим следующие два списка:
    [1,2,3]
    [4,5,6]
    Если упаковать их вместе, после простого преобразования типов данных, как вы увидите чуть ниже, получится новый список:
    [(1,4), (2,5), (3,6)]
    Распаковка их обратно в исходные кортежи состоит из двух этапов. Во- первых, необходимо убрать внешние квадратные скобки результата, чтобы получить следующие три кортежа:
    (1,4)
    (2,5)
    (3,6)
    Далее, если упаковать их вместе, получится новый список:
    [(1,2,3), (4,5,6)]
    Мы опять получили оба исходных списка! Следующий фрагмент кода де- монстрирует этот процесс полностью:
    lst_1 = [1, 2, 3]
    lst_2 = [4, 5, 6]
    # Упаковка двух списков вместе zipped = list(zip(lst_1, lst_2))
    print(zipped)
    # [(1, 4), (2, 5), (3, 6)]
    # Обратная распаковка списков lst_1_new, lst_2_new = zip(*zipped)
    print(list(lst_1_new))
    print(list(lst_2_new))
    Оператор
    *
    служит для распаковки  всех элементов списка. Этот опе- ратор удаляет внешние квадратные скобки списка zipped
    , так что на вход

    68
    Глава 2. Трюки Python функции zip()
    попадают три итерируемых объекта (кортежи
    (1,
    4),
    (2,
    5),
    (3,
    6)
    ). Если упаковать эти итерируемые объекты вместе, то первые три зна- чения кортежей
    1
    ,
    2
    и
    3
    будут упакованы в один новый кортеж, а вторые три значения кортежей
    4
    ,
    5
    и
    6
    — в другой новый кортеж. Вместе получатся итери- руемые объекты
    (1,
    2,
    3)
    и
    (4,
    5,
    6)
    , то есть исходные (неупакованные) данные.
    Теперь представьте, что работаете в IT-подразделении вашей компании.
    У вас есть база данных всех сотрудников с названиями столбцов 'name'
    ,
    'salary'
    и 'job'
    . Однако ваши данные не маркированы, они представляют собой просто набор строк вида
    ('Bob',
    99000,
    'mid-level manager')
    . Необ- ходимо связать эти названия столбцов с элементами данных и привести их в удобочитаемый вид:
    {'name':
    'Bob',
    'salary':
    99000,
    'job':
    'mid-level manager'}
    . Как это сделать?
    Код
    Наши данные состоят из названий столбцов и информации о сотрудниках в виде списка кортежей (строк). Связываем названия столбцов со строками, получая таким образом список ассоциативных массивов. Каждый из ассо- циативных массивов связывает названия столбцов с соответствующими элементами данных (листинг 2.10).
    Листинг 2.10. Однострочное решение для приведения списка кортежей в формат базы данных
    ## Данные column_names = ['name', 'salary', 'job']
    db_rows = [('Alice', 180000, 'data scientist'),
    ('Bob', 99000, 'mid-level manager'),
    ('Frank', 87000, 'CEO')]
    ## Однострочник db = [dict(zip(column_names, row)) for row in db_rows]
    ## Результат print(db)
    В каком же формате будет выведена база данных db
    ?
    1   2   3   4   5   6   7   8   9   ...   21


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