в чем хранить данные python
Python, введение в БД
Здравствуйте, здесь и сейчас я хочу рассказать, что такое базы данных, зачем они нужны, и т.д.; для работы с ними мы будем использовать python и его библиотеку sqlite3.
Так нам говорит Яндекс, но если сказать простыми словами, не углубляясь во все эти понятия, то:
То есть как в библиотеку мы можем прийти и взять книгу «Война и мир», зная что она будет лежать в разделе романов, на букву «В», так и из БД мы можем взять запись по определённому аргументу, в данном случае жанру.
И тут возникает вопрос.
И что бы ответить на этот вопрос, мы должны кое-что узнать.
Как хранятся данные в базах данных
Сначала нужно понять, что БД делятся на:
Сетевые и иерархические БД:
Такие БД представляют собой графы и хранят информацию в них же.
Данные БД здесь мы рассматривать не будем. Поэтому перейдём к реляционной БД.
Реляционные базы данных
Я думаю что, на вопрос мы ответили, и можно идти дальше.
Зачем нужны базы данных?
За всю жизнь, человечество накопила невероятно много информации, а БД, как мы знаем собирают, и сортирует эту информацию по таблицам (в нашем случае). И БД помогают абсолютно спокойно ориентироваться во всей этой куче информации, добавлять её туда, изменять и т.д.;
Из теории в практику
Сейчас мы пойдём в практику, но перед этим хотелось бы уточнить кое-что. Сверху я написал такую строку:
Мой косяк исправили, идём в практику!
Установка sqlite3
Да, это смешно, но мало ли кому-нибудь понадобится
Я не буду описывать алгоритм установки, ведь это давно сделали за меня, если вам нужно установить данный модуль, то просьба идти вот сюда.
Создание первой БД
cur = con.cursor — позволит нам производить операции с БД, остальное не важно.
cur.execute(. ) — создаёт таблицу с именем тест и всего 1 колонкой id, в которой все данные — числа
commit() — грубо говоря, сохранение БД
А давайте создадим программу, которая запрашивает имя и фамилию, и записывает их в БД, а потом по выбору цифр либо выводит, либо записывает снова.
Стандартные моменты пропустим.
cur.execute(«INS. ») — Добавление данных
cur.execute(«SeL. ») — Получение данных. И так как там отдаётся массив, то мы его перебираем, а после ещё и из кортежа данные берём.
«SELECT», «INSERT», «DROP» и т.д. — это всё SQL.
cur.fetchall() — это что бы в переменную записалось всё, что пришло из БД.
Вывод
Базы данных — важная и очень нужная вещь. Здесь мы затронули настолько её малую часть, что аж смешно. Поэтому чтобы действительно узнать как это работает, советую почитать об этом всём в интернете, благо информации много. Удачи!
Заметки Python #17: Формат хранения данных
Продолжая тему клиент-серверных приложений, затронем такой момент, как формат хранения данных, которые идут от этого самого клиенту к этому самому серверу.
Какие еще форматы данных?
Формат CSV
CSV (comma-separated value) — формат передачи данных в виде таблиц. Данные можно извлечь из самой таблицы — отдельная строка файла соответствует строке таблицы, а разделителем может быть не только запятая, но и любые другие.
Как выглядят данные записанные в формате CSV?
Это определенный набор списков. Первый — названия столбцов, все остальные — значения:
В Python есть специальный модуль для работы с этим форматом — csv. Чтобы прочитать данные с файла используется метод reader. В качестве параметра ей передается ссылка на файл (объект), с которого будет считана информация
import csv
with open(‘alco_data.csv’) as file:
read_file = csv.reader(file)
for data in read_file:
print(data)
import csv
with open(‘alco_data.csv’) as file:
read_file = csv.reader(file)
print(list(read_file))
Как отделить заголовки от содержимого в CSV?
Чтобы отделить заголовки от содержимого можно использовать метод next
import csv
with open(‘alco_data.csv’) as file:
read_file = csv.reader(file)
headers = next(read_file)
print(‘Headers: ‘, headers)
for data in read_file:
print(data)
Метод DictReader
В модуле csv есть отдельный метод для вывода данных таким образом, чтобы каждой строке таблицы соответствовал словарь (dict), в котором в котором элементы представляют собой связку
import csv
with open(‘alco_data.csv’) as file:
read_file = csv.DictReader(file)
for data in read_file:
print(data)
import csv
with open(‘alco_data.csv’) as file:
read_file = csv.DictReader(file)
for data in read_file:
print((data[‘store’], data[‘name’]))
По аналогии с чтением данных, в Питоне, с помощью модуля csv, можно записать данные формата csv в файл. Сделать это можно с помощью метода csv.writer(file)
data = [[‘store’, ‘alcohol’, ‘name’, ‘description’],
[‘magnit’, ‘Whisky’, ‘William Lawsons’, ‘Spiced, str’],
[‘ashan’, ‘Whisky’, ‘William Lawsons’, ‘Spiced, str’],
[‘perecrestok’, ‘Whisky’, ‘William Lawsons’, ‘Original, str’],
[‘pyaterochka’, ‘Whisky’, ‘William Lawsons’, ‘Original, str’]]
with open(‘alco_data_write.csv’, ‘w’) as file:
datawrite = csv.writer(file)
for info in data:
datawrite.writerow(info)
with open(‘alco_data_write.csv’) as file:
print(file.read())
Правилом хорошего тона считается указывать кавычки для каждого значения. Их можно не указывать, но часто это приветствуется:
data = [[‘store’, ‘alcohol’, ‘name’, ‘description’],
[‘magnit’, ‘Whisky’, ‘William Lawsons’, ‘Spiced, str’],
[‘ashan’, ‘Whisky’, ‘William Lawsons’, ‘Spiced, str’],
[‘perecrestok’, ‘Whisky’, ‘William Lawsons’, ‘Original, str’],
[‘pyaterochka’, ‘Whisky’, ‘William Lawsons’, ‘Original, str’]]
with open(‘alco_data_write.csv’, ‘w’) as file:
datawrite = csv.writer(file, quoting=csv.QUOTE_NONNUMERIC)
for info in data:
datawrite.writerow(info)
with open(‘alco_data_write.csv’) as file:
print(file.read())
Метод writerows
Метод writecows создан для передачи объекта (список, кортеж), в которых содержаться данные, в качестве аргумента. Это избавит от построчного записывания данных в файл.
data = [[‘store’, ‘alcohol’, ‘name’, ‘description’],
[‘magnit’, ‘Whisky’, ‘William Lawsons’, ‘Spiced, str’],
[‘ashan’, ‘Whisky’, ‘William Lawsons’, ‘Spiced, str’],
[‘perecrestok’, ‘Whisky’, ‘William Lawsons’, ‘Original, str’],
[‘pyaterochka’, ‘Whisky’, ‘William Lawsons’, ‘Original, str’]]
with open(‘alco_data_write.csv’, ‘w’) as file:
datawrite = csv.writer(file, quoting=csv.QUOTE_NONNUMERIC)
datawrite.writerows(data)
with open(‘alco_data_write.csv’) as file:
print(file.read())
Метод DictWriter
DictWriter — метод из модуля csv, которые работает только со словарями Python версии от 3.6 — необходимо явно указывать порядок следования столбцов в файле. За это отвечает параметр fieldnames. Можно указать свой разделитель с помощью параметра delimiter
data = [[‘store’, ‘alcohol’, ‘name’, ‘description’],
[‘magnit’, ‘Whisky’, ‘William Lawsons’, ‘Spiced, str’],
[‘ashan’, ‘Whisky’, ‘William Lawsons’, ‘Spiced, str’],
[‘perecrestok’, ‘Whisky’, ‘William Lawsons’, ‘Original, str’],
[‘pyaterochka’, ‘Whisky’, ‘William Lawsons’, ‘Original, str’]]
with open(‘alco_data_write.csv’, ‘w’) as file:
datawrite = csv.writer(file, delimiter=’/’)
for info in data:
datawrite.writerow(info)
with open(‘alco_data_write.csv’) as file:
print(file.read())
Формат JSON
JSON — популярный в web’е формат передачи, хранения и обмена данными. Конечно же в Питоне тоже есть специальный модуль для работы с такими данными — json. Как выглядит обычный JSON-файл? Что у него внутри?
<
«action»: «msg»,
«to»: «morisk»,
«from»: «me»,
«encoding»: «ascii»,
«message»: «Buy Whisky»
>
Как прочитать JSON-формат в Python?
Для чтения данных из JSON-объектов используются методы load и loads модуля json. Первый считывает файл в JSON-формате и возвращает python-объекты. Второй — отвечает за считывание строки в JSON-формате и тоже возвращает python-объекты
#метод load (обычное чтение json-файла)
with open(‘alco_json.json’) as file:
data = json.load(file)
print(type(data)) #класс — словарь
for section, commands in data.items():
print(section)
print(commands)
#метод loads (чтение json-строк)
with open(‘alco_json.json’) as file:
filedata = file.read()
print(type(filedata)) #класс — строка
object = json.loads(filedata)
print(type(object)) #класс — словарь
for section, commands in object.items():
print(section)
print(commands)
Как записать JSON-формат в Python?
with open(‘alco_json.json’, ‘w’) as file:
file.write(json.dumps(jsonwrite))
with open(‘alco_json.json’) as file:
print(file.read())
jsonwrite = < #метод dump
«action»: «msg»,
«to»: «morisk»,
«from»: «me»,
«encoding»: «ascii»,
«message»: «Buy Whisky»
>
with open(‘alco_json.json’, ‘w’) as file:
json.dump(jsonwrite, file, sort_keys=True, indent=2)
with open(‘alco_json.json’) as file:
print(file.read())
Как преобразуются данные при сериализации JSON?
Python | JSON |
dict | object |
list, tuple | array |
str | string |
int, float | number |
True | true |
False | false |
None | null |
JSON | Python |
object | dict |
array | list |
string | str |
number (int) | int |
number (real) | float |
true | True |
false | False |
При использовании формата JSON есть ограничение: нет возможности сохранить словарь, где в качестве ключей — кортежи
Формат YAML
YAML («Ain’t Markup Language») — формат сериализации данных, который считают максимально user-friendly по синтаксису и удобству форматирования данных. Структура и синтаксис практически такой же, как на Python — используются отступы, сделанные с помощью пробелов (использовать tab нельзя). Список в YAML — структурирован. При этом каждый элемент записывается в своей строке и маркируется символом «- » (обязательно с пробелом после него). Все строки набора должны иметь одинаковую величину отступа. Все эти же правила справедливы и для типа данных «словарь» (dict). В YAML так же могут быть комбинации элементов в словаре (dict) каждому ключу будет соответствовать набор элементов в виде списка (list)
# список с элементами (строки)
[‘action’, ‘to’, ‘from’, ‘encoding’, ‘message’]
# структурированный список
— action
— to
— from
— encoding
— message
# словарь в виде блока
‘action’: ‘msg’
‘to’: ‘account_name’
# спецсимволы в строках
command: «action | to»
# примеры комбинаций элементов
# словарь с элементами-списками
message:
— msg_1
— msg_2
— msg_3
to:
— account_1
— account_2
— account_3
# список словарей
— action: msg_1
to: account_1
— action: msg_2
to: account_2
Как считать YAML-формат?
Для работы с YAML, как и с другими типами данных, в Python заготовлен отдельный модуль — yaml
with open(‘alco_yaml_listdict.yaml’) as file:
data = yaml.load(file, Loader=yaml.FullLoader)
print(data)
alco_list = [‘lawsons’,
‘captain morgan’,
‘bells’]
zapivon_list = [‘coca-cola’,
‘pepsi’,
‘not_zapivon’]
Лучшие способы сохранения данных в Python
Привет читатели! В этом руководстве мы будем иметь дело с тем, как мы можем эффективно сохранять данные в Python.
Привет читатели! В этом руководстве мы будем иметь дело с тем, как мы можем эффективно сохранять данные в Python.
Как сохранить данные в Python?
Когда мы работаем над приложениями Python, мы будем иметь дело с объектами Python напрямую, так как все является объектом в Python. Давайте посмотрим на некоторые способы, которыми мы можем легко хранить их!
1. Использование сочинения для хранения объектов Python
Если мы хотим держать вещи простыми, мы можем использовать модуль сортировки, который является частью стандартной библиотеки для сохранения данных в Python.
Мы можем «сортировать» объекты Python в пиловый файл, который мы можем использовать для сохранения данных/загрузки данных.
Поэтому, если у вас есть пользовательский объект, который вам может потребоваться хранить/извлекать, вы можете использовать этот формат:
Чтобы снова загрузить один и тот же объект, мы могли бы использовать Pickle.Load () используя аналогичную логику.
Мы только что успешно восстановили наши старые данные!
2. Использование SQLite3 для постоянного сохранения данных в Python
Если вы хотите использовать постоянную базу данных для сохранения данных в Python, вы можете использовать SQLite3 Библиотека, которая предоставляет вам API для использования баз данных SQLite.
Опять же, это часть стандартной библиотеки, поэтому нет необходимости устанавливать ничего!
Однако, поскольку это реляционная база данных, вы не можете напрямую давить объекты Python, как в Парил Отказ
Вам придется сериализовать и десериализировать их в соответствующие типы баз данных.
Посмотрите на некоторые примеры, вы можете обратиться к этой статье на использовании SQLite в Python.
3. Использование SQLICENCT в качестве постоянного кэша
Если вы найдете использование SQLite3 Слишком утомительно, есть гораздо лучшее решение! Вы можете использовать sqlized Для хранения постоянных данных, и это внутренне использует SQLite3 база данных для обработки хранилища.
Вы должны установить этот пакет, используя PIP:
Единственное, что вы должны иметь в виду, это то, что вам нужно использовать Ключ: значение отображения для хранения/извлечения данных, как и словарь!
Вот очень простой пример, используя MyClass пример.
Действительно, мы просто загрузили наш объект Python! Если вы заметите, sqlized создаст базу данных cache.sqlite3 автоматически, если оно не существует, а затем используйте его для хранения/загрузки данных.
Заключение
В этой статье мы смотрели, как мы можем использовать Python для хранения данных по-разному.
Как работает память в Python
Что такое память и зачем она нужна?
Ни одна компьютерная программа не может работать без данных. А данные, чтобы программа имела к ним доступ, должны располагаться в оперативной памяти вашего компьютера. Но что такое оперативная память на самом деле? Когда произносишь это словосочетание, многие сразу представляют «железную» плашку, вставленную в материнскую плату, на которой написано что-то типа 16Gb DDR4 2666MHz. И они, разумеется, правы — это действительно физический блок оперативной памяти, в котором, в итоге, все данные и оказываются. Но прежде, чем стать доступной внутри вашей программы, на память (как и на всё остальное аппаратное обеспечение) накладывается куча абстракций.
Во-первых, есть операционная система, которая посредством диспетчера (менеджера) оперативной памяти абстрагирует физическую оперативную память, позволяет реализовать механизмы SWAP-файлов и др.
Во-вторых, внутри операционной системы, есть абстракция, называемая «процесс», которая, в том числе, предназначена для изоляции и упрощения работы с ресурсами отдельными программами. Именно процесс «делает вид», что независимо от количества запущенных программ и объема установленной в компьютер оперативной памяти, вашей программе доступно 4 ГБ RAM (на 32-разрядных системах) или сильно больше (на 64-разрядных).
Долгое время, компьютерным программам, хватало этого набора абстракций. Вам нужны данные, вы хотите с ними поработать? Всё просто:
Попросите у процесса (ОС) выделить вам немного (одну или несколько страниц) оперативной памяти.
Верните ее в операционную систему.
Такой подход позволял работать с памятью максимально эффективно. Вы точно знали, сколько реально вам памяти выделено, зачем вы ее используете, и т.д. и т.п. Однако помимо преимуществ подход имеет и ряд недостатков. Ключевой из них — сложность. Управлять памятью вручную — это сложно и тяжело. Легко забыть что-то удалить или вернуть страницу операционной системе, и сразу возникает утечка: программа держит неиспользуемую память просто так, не давая применять ее для решения других задач.
Время шло, и в борьбе с этой проблемой постепенно появлялись новые инструменты и возможности. Одной из них стала концепция управляемой памяти, когда не вы, а runtime или библиотеки вашего языка программирования самостоятельно занимаются очисткой памяти. Это, пускай и жертвуя немного эффективностью, позволило сильно сократить трудозатраты на управление памятью и повысить надежность этого процесса.
Механизм памяти в Python
Python — это язык с управляемой памятью. Причем для управления ею он использует несколько механизмов. Я постараюсь коротко осветить основные из них. Для зануд сразу подчеркну, что под Python’ом я понимаю конкретную реализацию CPython, а не какие-то другие версии, в которых всё может работать по-другому 🙂
При запуске Python-программы создается новый процесс, в рамках которого операционная система выделяет пул ресурсов, включая виртуальное адресное пространство. В эту память загружается интерпретатор Python вместе со всеми необходимыми ему для работы данными, включая код вашей программы.
Оставшаяся свободная виртуальная память может использоваться для хранения информации об объектах Python’а. Для управления этой памятью в CPython используется специальный механизм, который называется аллокатор. Он используется каждый раз, когда вам нужно создать новый объект.
Обычно мы в своих программах не оперируем большими объектами. Большая часть наших данных — это числа, строки и т.п., они занимают не такой уж большой объем в расчёте на одно значение. Но зато мы создаем их достаточно часто. И это приводило бы к проблемам, если бы Python абсолютно все такие вызовы транслировал в операционную систему. Системный вызов на выделение памяти — штука трудозатратная, зачастую связанная с переходом в контекст ядра операционной системы и т.п. Поэтому одна из главных задач аллокатора Python — оптимизация количества системных вызовов.
Ремарка. Для больших объектов (больше 512 байт) Python выделяет память напрямую у ОС. Обычно таких объектов не очень много в рамках программы, и создаются они нечасто. Поэтому накладные расходы на создание таких объектов напрямую в RAM не так высоки.
Как же устроен аллокатор внутри? Он состоит из частей трёх видов:
Арена — большой непрерывный кусок памяти (обычно 256 килобайт), содержит несколько страниц виртуальной памяти операционной системы.
Пул — одна страница виртуальной памяти (обычно 4 килобайта).
Блок — маленький кусочек памяти, используемый для хранения одного объекта.
Давайте поговорим о них подробнее. Когда Python’у нужно расположить какой-то объект в оперативной памяти он ищет подходящую арену. Если такой нету, он запрашивает новую арену у операционной системы. Что значит «подходящую»? Арены организованы в двусвязный список и отсортированы от самой заполненной к самой свободной. Для добавления нового объекта выбирается САМАЯ ЗАПОЛНЕННАЯ арена. Почему такая странная логика? Это связано с политикой освобождения памяти. Арены — единственное место, в котором происходит запрос и освобождение памяти в Python. Если какая-то арена полностью освобождается от объектов, она возвращается назад операционной системе и память освобождается. Таким образом, чем компактнее живут объекты в рамках арен, тем ниже общее потребление оперативной памяти программой.
Внутри арен расположены пулы. Каждый пул предназначен для хранения блоков одинакового размера (то есть в одном пуле могут быть только блоки одного и тоже размера, при этом в арене могут быть пулы с разными размерами блоков).
Каждый пул может быть в одном из трех состояний — used, full и empty. Full означает, что пул полностью занят и не может принять новые объекты. Empty — что пул полностью пустой и может быть использован для хранения новых объектов (при этом пустой пул может быть использован для хранения объектов любого размера). Used — это пул, который используется для хранения объектов, но при этом еще не заполнен полностью.
Python поддерживает списки пулов каждого из размеров и отдельно список пустых пулов. Если вы хотите создать новый объект, то Python сначала пытается найти used-пул с нужным размером блока и расположить объект там. Если used-пула нет, тогда берется empty-пул, и объект создается в нем (а сам пул из статуса empty переводится в статус used). Если и empty-пулов нет, то запрашивается новая арена.
Внутри пула живут блоки. Каждый блок предназначен для хранения одного объекта. В целях унификации размеры блоков фиксированы. Они могут быть размером 8, 16, 24, 32 …. 512 байт. Если Вам нужно 44 байта для хранения объекта, то он будет расположен в блоке на 48 байт. Каждый пул содержит список свободных и занятых блоков (на самом деле, есть еще untouched-блоки, в которых никогда не жили данные, но по сценариям использования они похожи на free-блоки, поэтому не будем на них останавливаться подробно). Когда вы хотите разместить новый объект, берется первый свободный блок, и объект располагается в нем. Когда объект удаляется, его блок помещается в список свободных.
Время жизни объекта и при чем тут GIL
Поговорив о том, как происходит выделение и освобождение памяти в Python, стоит отдельно поговорить о том, а как язык управляет временем жизни. Для этого в Python реализовано два механизма:
Механизм сборки мусора.
Каждый объект в Python — это, в первую очередь, объект, унаследованный от базового класса PyObject. Этот самый PyObject содержит всего два поля: ob_refcnt — количество ссылок, и ob_type — указатель на другой объект, тип данного объекта.
К сожалению, счетчик ссылок подвержен проблемам в многопоточной среде. Состояния гонки могут приводит к некорректности обновления этого счетчика из разных потоков. Чтобы этого избежать CPython использует GIL — Global Interpreter Lock. Каждый раз, когда происходит работа с памятью, GIL — как глобальная блокировка — препятствует выполнению этих действий одновременно из двух потоков. Он гарантирует, что сначала отработает один, потом другой.
Второй механизм очистки памяти — это сборщик мусора (garbage collector), основанный на идее поколений. Зачем он нам нужен, если есть счетчик ссылок? Дело в том, что счетчик ссылок не позволяет отслеживать ситуации с кольцевыми зависимостями, когда объект A содержит ссылку на B, а B — на A. В таком случае, даже если никто больше не ссылается на объекты A и B, их счетчик всё равно никогда не станет равным нулю и они никогда не удалятся через механизм счетчика ссылок. Для борьбы с такими зависимостями и появился второй механизм (как модуль gc, начиная с версии Python 1.5).
Работает он следующим образом: GC отслеживает объекты (объекты-контейнеры, которые могут содержать ссылки на другие объекты) и смотрит, доступны ли они из основного кода на Python. Если нет, то сборщик их удаляет. Если да — оставляет.
В отличие от счетчика ссылок, механизм сборки мусора не работает постоянно. Он запускается от случая к случаю на основе эвристик. GC разделяет объекты на три поколения. Каждый новый объект начинает свой путь с первого поколения. Если объект переживает раунд сборки мусора, он переходит к более старому поколению. В младших поколениях сборка происходит чаще, чем в старших. Эта практика является стандартной для такого рода сборщиков мусора и снижает частоту и объем очищаемых данных. Идея простая: чем дольше живет объект, тем с большей вероятностью он проживет еще. То есть новые объекты удаляются гораздо чаще, чем те, которые уже просуществовали достаточно долго.
Каждое поколение имеет индивидуальный счётчик и порог. Счетчик хранит количество созданных минус количество удаленных объектов с момента последнего сбора. Каждый раз, когда вы создаете новый объект, Python проверяет, не превысил ли счетчик поколения пороговое значение. Если это так, Python инициирует процесс сборки мусора.
Итоги
Вот так и устроен процесс работы с памятью в Python. Его понимание помогает лучше понять, как работают ваши программы внутри, а значит и писать более эффективный и высокопроизводительный код.
Что осталось за рамками статьи?
Мы не поговорили еще о многих вещах:
Об оптимизации хранения небольших чисел.
О работе с большими файлами через Memory Mapping.