Шаг 31.
Однострочники Python.
Трюки Python. Форматирование баз данных с помощью функции zip()

    На этом шаге мы узнаем, как задать названия столбцов базы данных для списка строк с помощью функции zip().

Общее описание

    Функция 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((1)*zipped) 
print(list(lst_1_new)) 
print(list(lst_2_new))

    Оператор * служит для распаковки (1) всех элементов списка. Этот оператор удаляет внешние квадратные скобки списка zipped, так что на вход функции 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?

Принцип работы

    Мы создали список с помощью спискового включения. Контекст состоит из кортежей для всех строк в переменной db_rows. Выражение zip(column_names, row) упаковывает вместе схему и строки. Например, первым из созданных списковым включением элементов будет zip(['name', 'salary', 'job'], ('Alice', 180000, 'data scientist')), объект, который после преобразования в список приобретает вид [('name', 'Alice'), ('salary', 180000), ('job', 'data scientist')]. Форма элементов - (ключ, значение), поэтому можно преобразовать их в ассоциативный массив с помощью функции преобразования dict(), чтобы получить желаемый формат базы данных.


Для функции zip() не важно, что одно из входных значений - список, а другое - кортеж. Ей необходимо только, чтобы входные данные представляли собой итерируемые объекты (а и списки, и кортежи - итерируемые).

    Результаты выполнения этого однострочного фрагмента кода таковы:

## Результат print(db)
# [{'name': 'Alice', 'salary': 180000, 'job': 'data scientist'}, 
#  {'name': 'Bob', 'salary': 99000, 'job': 'mid-level manager'}, 
#  {'name': 'Frank', 'salary': 87000, 'job': 'CEO'}]

    Теперь всем элементам данных соответствуют названия в списке ассоциативных массивов. Вы научились эффективно использовать функцию zip().

    На следующем шаге мы подведем некоторые итоги.




Предыдущий шаг Содержание Следующий шаг