Сохранение данных в оперативной памяти python

Обновлено: 06.07.2024

Можно ли хранить данные Python (или C ++) в ОЗУ для последующего использования и как этого достичь?

Фон:
Я написал программу, которая находит, какие строки во входной таблице соответствуют заданному регулярному выражению. Я могу найти все строки примерно за одну секунду или меньше. Однако проблема в том, что я обрабатываю входную таблицу в объект Python каждый раз, когда запускаю эту программу. Этот процесс занимает около 30 минут.

ПРИМЕЧАНИЕ. Объект python не будет изменен после создания. Однако мне нужно иметь возможность воссоздать этот объект, если это необходимо.

Решение

Большинство операционных систем также позволяют вам устанавливать объем оперативной памяти в качестве диска. ОЗУ . Вы могли бы написать (как предложил Нил) объекты для этого.

Другие решения

Вы можете попробовать выбрать ваш объект и сохранить его в файл, чтобы при каждом запуске программы просто десериализовать объект, а не пересчитывать его. Надеемся, что дисковый кеш сервера сохранит файл горячим, если это необходимо.

Мы регулярно загружаем и храним гораздо большие куски памяти, чем 2 Гб за мгновение (секунды). Мы можем получить 350 Мбит / с от нашего 3-летнего SAN.

Узкие места / накладные расходы связаны, в основном, с управлением объектами Python. Я считаю, что использование маршала намного быстрее, чем cPickle. В сочетании с использованием структур данных, в которых задействованы минимальные дескрипторы объектов Python, это более чем достаточно быстро.

Для структур данных вы можете использовать array.array или же numpy , array.array немного более переносимым (без дополнительных библиотек), но numpy гораздо удобнее во многих отношениях.
Например, вместо 10 миллионов целых чисел (объектов Python), вы бы создали один array.array('i') с 10 миллионами элементов.

Лучшая часть использования маршала состоит в том, что это очень простой формат, в который можно легко писать и читать, используя код на языке c / c ++.

Ваше описание проблемы довольно расплывчато и может быть прочитано несколькими способами.

Один из способов, с помощью которого я прочитал это, заключается в том, что у вас есть какое-то представление ASCII структуры данных на диске. Вы читаете это представление в память, а затем просматриваете его один или несколько раз, ища вещи, которые соответствуют заданному регулярному выражению.

Ускорение этого зависит очень много от рассматриваемой структуры данных.

Если вы просто делите строку, то, возможно, вам следует просто прочитать все это в байтовый массив, используя одну инструкцию чтения. Затем вы можете изменить способ grep для использования grep с байтовым массивом, который не занимает несколько строк. Если вы возитесь с выражением, чтобы всегда соответствовать целую строку, поставив ^.*? в начале и .*?$ в конце ( ? вынуждает использовать минимальное значение вместо максимального значения munch), затем вы можете проверить размер соответствующего выражения, чтобы узнать, сколько байтов вперед.

Кроме того, вы можете попробовать использовать mmap модуль для достижения чего-то подобного без необходимости что-либо читать и нести копию накладных расходов.

А сохранение его в памяти и использование демона не гарантирует, что он останется в памяти. Это просто гарантирует, что он останется созданным в виде структуры данных, которую вы хотите в пределах адресного пространства процесса Python. ОС может принять решение об обмене этой памяти на диск в любое время.

Опять же, это означает, что фокусирование на времени для чтения с диска, вероятно, не является правильным. Вместо этого сосредоточьтесь на том, как эффективно воссоздать (или сохранить) структуру данных в адресном пространстве процесса Python.

Во всяком случае, это моя многословная болтовня по теме. Учитывая неопределенность вашего вопроса, однозначного ответа нет, поэтому я просто дал шведский стол возможных приемов и некоторых руководящих идей.


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

Диспетчер памяти: «командовать парадом буду я»

Python — это интерпретируемый язык программирования, поэтому перед запуском программы код на языке Python компилируется в машиночитаемые инструкции — байт-код . Инструкции байт-кода интерпретируются виртуальной машиной, определяемой реализацией языка, например, стандартной — CPython .

Доклад Егора Овчаренко «Устройство CPython» поможет разобраться в стандартной реализации Python

Оговоримся, что CPython не взаимодействует напрямую с регистрами и ячейками физической памяти — только с ее виртуальным представлением. В начале выполнения программы операционная система создает новый процесс и выделяет под него ресурсы. Выделенную виртуальную память интерпретатор использует для 1) собственной корректной работы, 2) стека вызываемых функций и их аргументов и 3) хранилища данных, представленного в виде кучи .

В отличие от C/C++, мы не можем управлять состоянием кучи напрямую из Python. Функции низкоуровневой работы с памятью предоставляются Python/C API , но обычно интерпретатор просто обращается к хранилищу данных через диспетчер памяти Python (memory manager).

Диспетчер памяти — своеобразный портье, который регистрирует и расселяет гостей отеля. Каждый постоялец получает ключ с номером комнаты, так что ни один из гостей не может заселиться не в свой номер. Две программы не могут одновременно записать переменную в одно место виртуальной памяти.

Фактически за это отвечает даже не диспетчер задач, который ожидает гостей за регистрационной стойкой, а GIL — глобальная блокировка интерпретатора. GIL гарантирует: в один и тот же момент времени байт-код выполняется только одним потоком. Главное преимущество — безопасная работа с памятью, а основной недостаток в том, что многопоточное выполнение программ Python требует специфических решений.

Очевидно, программа не сама выполняет сохранение и освобождение памяти — ведь мы не пишем соответствующих инструкций. Интерпретатор лишь запрашивает диспетчер памяти сделать это. А диспетчер уже делегирует работу, связанную с хранением данных, аллокаторам — распределителям памяти.

Организация доступной виртуальной памяти

Непосредственно с оперативной памятью взаимодействует распределитель сырой памяти (raw memory allocator). Поверх него работают аллокаторы, реализующие стратегии управления памятью, специфичные для отдельных типов объектов. Объекты разных типов — например, числа и строки — занимают разный объем, к ним применяются разные механизмы хранения и освобождения памяти. Аллокаторы стараются не занимать лишнюю память до тех пор, пока она не станет совершенно необходимой — этот момент определен стратегией распределения памяти CPython.

Python использует динамическую стратегию, то есть распределение памяти выполняется во время выполнения программы. Виртуальная память Python представляет иерархическую структуру, оптимизированную под объекты Python размером менее 256 Кб:

  • Арена — фрагмент памяти, расположенный в пределах непрерывного блока оперативной памяти объемом 256 Кб. Объекты размером более 256 Кб направляются в стандартный аллокатор C.
  • Пул — блок памяти внутри арены, занимающий 4 Кб, что соответствует одной странице виртуальной памяти. То есть одна арена включает до 256/4 = 64 пулов.
  • Блок — элемент пула размером от 16 до 512 байт. В пределах пула все блоки имеют одинаковый размер. Размер блока определяется тем, сколько байт требуется для представления конкретного объекта. Размеры блоков кратны 16 байт. То есть существует всего 512/16 = 32 классов ( size class ) блоков. То есть в одном пуле, в зависимости от класса, может находиться от 8 до 256 блоков.

Блок содержит не более одного объекта Python и находится в одном из трех состояний:

  1. untouched — блок еще не использовался для хранения данных;
  2. free — блок использовался механизмом памяти, но больше не содержит используемых программой данных;
  3. allocated — блок хранит данные, необходимые для выполнения программы.

В пределах пула блоки free организованы в односвязный список с указателем freeblock . Если аллокатору для выделения памяти не хватит блоков списка freeblock , он задействует блоки untouched . Освобождение памяти означает всего лишь то, что аллокатор меняет статус блока с allocated на free и начинает отслеживать блок в списке freeblock .

Пул может находиться в одном из трех состояний: used (занят), full (заполнен), empty (пуст). Пустые пулы отличаются от занятых отсутствием блоков allocated и тем, что для них пока не определен size class . Пулы full полностью заполнены блоками allocated и недоступны для записи. Стоит освободиться любому из блоков заполненного пула — и он помечается как used .

Пулы одного типа и одного размера блоков организованы в двусвязные списки. Это позволяет алгоритму легко находить доступное пространство для блока заданного размера. Алгоритм проверяет список usedpools и размещает блок в доступном пуле. Если в usedpools нет ни одного подходящего пула для запроса, алгоритм использует пул из списка freepools , который отслеживает пулы в состоянии empty .

Арена

Арены содержат пулы любых видов и организованы в двусвязный список usable_arenas . Список отсортирован по количеству доступных пустых пулов. Чем меньше в арене таких пулов, тем она ближе к началу списка. Для размещения новых данных выбирается область, наиболее заполненная данными.

Информацию о текущем распределении памяти в аренах, пулах и блоках можно посмотреть, запустив функцию sys._debugmallocstats() :

Чтобы не произошло утечки памяти, диспетчер памяти должен отследить, что вся выделенная память освободится после завершения работы программы. То есть при завершении программы CPython дает задание очистить все арены.

Именно количество используемых арен определяет объем оперативной памяти, занимаемой программой на Python — если в арене все пулы в состоянии empty , СPython делает запрос на освобождение этого участка виртуальной памяти. Но уже понятно: чтобы пулы стали empty , все их блоки должны быть free или untouched . Получается, нужно понять, как CPython освобождает память.

Освобождение памяти: счетчик ссылок, сборщик мусора

Для освобождения памяти используются два механизма: счетчик ссылок и сборщик мусора.

Всё в Python является объектами, а прародителем всех типов объектов в реализации CPython является PyObject . От него наследуются все остальные типы. В PyObject определены счетчик ссылок и указатель на фактический тип объекта. Счетчик ссылок увеличивается на единицу, когда мы создаем что-то, что обращается к объекту, например, сохраняем объект в новой переменной. И наоборот, счетчик уменьшается на единицу, когда мы перестаем ссылаться на объект.

Счетчик ссылок любого объекта можно проверить с помощью sys.getrefcount() . Учтите, что передача объекта в getrefcount() увеличивает счетчик ссылок на 1, так как сам вызов метода создает еще одну ссылку. Когда счетчик уменьшается до нуля, происходит вызов аллокатора для освобождения соответствующих блоков памяти.

Однако счетчик ссылок неспособен отследить ситуации с циклическими ссылками. К примеру, возможна ситуация, когда два объекта ссылаются друг на друга, но оба уже не используются программой. Для борьбы с такими зависимостями используется сборщик мусора ( garbage collector ).

Если счетчик ссылок является свойством объекта, то сборщик мусора — механизм, который запускается на основе эвристик. Задача этих эвристик — снизить частоту и объем очищаемых данных. Основная стратегия заключается в разделении объектов на поколения: чем больше сборок мусора пережил объект, тем он значимее для выполнения работы программы. Сборщик мусора имеет интерфейс в виде модуля gc .

Заключение

Сохранение и освобождение блоков памяти требует времени и вычислительных ресурсов. Чем меньше блоков задействовано, тем выше скорость работы программы. Позволим себе дать несколько советов, касающихся экономной работы с памятью:

  1. Обращайте внимание на работу с неизменяемыми объектами . К примеру, вместо использования оператора + для соединения строк используйте методы .join() , .format() или f-строки.
  2. Избегайте вложенных циклов. Создание сложных вложенных циклов приводит к генерации чрезмерно большого количества объектов, занимающих значительную часть виртуальной памяти. Большинство задач, решаемых с помощью вложенных циклов, разрешимы методами модуля itertools.
  3. Используйте кэширование . Если вы знаете, что функция или класс используют или генерируют набор однотипных объектов, применяйте кэширование . Часто для этого достаточно добавить всего лишь один декоратор из библиотеки functools .
  4. Профилируйте код. Если программа начинает «тормозить», то профилирование — самый быстрый способ найти корень всех зол.

На ранних этапах работы с кодом Python можно вполне обойтись стандартными средствами Python. Но по мере разрастания кодовой базы и приближения к коммерческому использованию кода производительность становится одним из ключевых факторов. Многие задачи, связанные с производительностью Python, лежат в области понимания устройства инструмента и конкретной реализации языка. Не пожалейте времени на изучение исходного кода CPython, находящегося в свободном доступе в репозитории на GitHub .

На Python создают прикладные приложения, пишут тесты и бэкенд веб-приложений, автоматизируют задачи в системном администрировании, его используют в нейронных сетях и анализе больших данных. Язык можно изучить самостоятельно, но на это придется потратить немало времени. Если вы хотите быстро понять основы программирования на Python, обратите внимание на онлайн-курс «Библиотеки программиста». За 30 уроков (15 теоретических и 15 практических занятий) под руководством практикующих экспертов вы не только изучите основы синтаксиса, но и освоите две интегрированные среды разработки (PyCharm и Jupyter Notebook), работу со словарями, парсинг веб-страниц, создание ботов для Telegram и Instagram, тестирование кода и даже анализ данных. Чтобы процесс обучения стал более интересным и комфортным, студенты получат от нас обратную связь. Кураторы и преподаватели курса ответят на все вопросы по теме лекций и практических занятий.

В этом руководстве мы узнаем, как Python управляет памятью или как обрабатывает наши данные внутренне. Это руководство даст глубокое понимание основ управления памятью Python. Когда мы выполняем наш скрипт, в его памяти запускается много логических процессов, чтобы сделать код эффективным.

Вступление

Управление памятью в Python очень важно для разработчиков программного обеспечения для эффективной работы с любым языком программирования. Мы не можем упускать из виду важность управления памятью при реализации большого количества данных. Неправильное управление памятью приводит к замедлению работы приложения и серверных компонентов. Это также становится причиной неправильной работы. Если память не используется должным образом, предварительная обработка данных займет много времени.

В Python памятью управляет менеджер Python, который определяет, куда поместить данные приложения в память.

Предположим, что память выглядит как пустая книга, и мы хотим написать что-нибудь на странице книги. Когда мы записываем любые данные, менеджер находит свободное место в книге и передает их приложению. Процедура предоставления памяти объектам называется распределением.

С другой стороны, когда данные больше не используются, они могут быть удалены менеджером памяти Python. Но вопрос в том, как? А откуда взялось это воспоминание?

Распределение памяти Python

  • Распределение статической памяти
  • Распределение динамической памяти

Статической памяти

Размещение стека

Структура данных Stack используется для хранения статической памяти. Это необходимо только внутри конкретной функции или вызова метода. Функция добавляется в стек вызовов программы всякий раз, когда мы ее вызываем. Назначение переменной внутри функции временно сохраняется в стеке вызова функции; функция возвращает значение, и стек вызовов переходит к текстовой задаче. Компилятор обрабатывает все эти процессы, поэтому нам не нужно об этом беспокоиться.

Стек вызовов(структура данных стека) содержит рабочие данные программы, такие как подпрограммы или вызовы функций, в порядке их вызова. Эти функции выходят из стека при вызове.

Динамической памяти

Как мы знаем, все в Python является объектом, а это означает, что динамическое распределение памяти вдохновляет управление памятью Python. Диспетчер памяти Python автоматически исчезает, когда объект больше не используется.

Распределение памяти в куче

Структура данных кучи используется для динамической памяти, которая не имеет отношения к именованию аналогов. Это тип памяти, который используется вне программы в глобальном пространстве. Одним из лучших преимуществ кучи памяти является то, что она освобождает пространство памяти, если объект больше не используется или узел удален.

В приведенном ниже примере мы определяем, как переменная функции хранится в стеке и куче.

Реализация Python по умолчанию

В основном язык Python написан на английском языке. Однако это определено в справочном руководстве, что само по себе бесполезно. Итак, нам нужен код, основанный на интерпретаторе правила в руководстве.

Преимущество реализации по умолчанию заключается в том, что она выполняет код Python на компьютере, а также преобразует наш код Python в инструкции. Итак, мы можем сказать, что реализация Python по умолчанию удовлетворяет обоим требованиям.

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

Сборщик мусора Python

Как мы объясняли ранее, Python удаляет те объекты, которые больше не используются, можно сказать, что освобождает пространство памяти. Этот процесс удаления ненужного пространства памяти объекта называется сборщиком мусора. Сборщик мусора Python запускает свое выполнение вместе с программой и активируется, если счетчик ссылок падает до нуля.

Когда мы назначаем новое имя или помещаем его в контейнеры, такие как словарь или кортеж, счетчик ссылок увеличивает свое значение. Если мы переназначаем ссылку на объект, счетчик ссылок уменьшает свое значение. Он также уменьшает свое значение, когда ссылка на объект выходит за пределы области видимости или объект удаляется.

Как мы знаем, Python использует динамическое выделение памяти, которым управляет структура данных Heap. Куча памяти содержит объекты и другие структуры данных, которые будут использоваться в программе. Диспетчер памяти Python управляет выделением или отменой выделения пространства кучи с помощью функций API.

Объекты Python в памяти

Как мы знаем, в Python все является объектом. Объект может быть простым(содержащий числа, строки и т. д.) или контейнером(словарь, списки или определенные пользователем классы). В Python нам не нужно объявлять переменные или их типы перед их использованием в программе.

Давайте разберемся в следующем примере.

Как видно из вышеприведенного вывода, мы присвоили значение объекту x и распечатали его. Когда мы удаляем объект x и пытаемся получить доступ в дальнейшем коде, будет ошибка, утверждающая, что переменная x не определена.

Следовательно, сборщик мусора Python работает автоматически, и программистам не нужно беспокоиться об этом, в отличие от C.

Подсчет ссылок в Python

Подсчет ссылок показывает, сколько раз другие объекты ссылаются на данный объект. Когда назначается ссылка на объект, счетчик объектов увеличивается на единицу. Когда ссылки на объект удаляются, количество объектов уменьшается. Когда счетчик ссылок становится равным нулю, диспетчер памяти Python выполняет освобождение. Давайте сделаем это простым для понимания.

Предположим, есть две или более переменных, которые содержат одно и то же значение, поэтому виртуальная машина Python скорее создает другой объект с таким же значением в частной куче. Фактически это указывает на то, что вторая переменная указывает на изначально существующее значение в частной куче.

Это очень полезно для сохранения памяти, которая может использоваться другой переменной.

Подсчет ссылок

Когда мы присваиваем значение переменной x, целочисленный объект 10 создается в памяти кучи, и его ссылка присваивается x.

y = x

В приведенном выше коде мы присвоили y = x, что означает, что объект y будет ссылаться на тот же объект, потому что Python выделил ту же ссылку на объект новой переменной, если объект уже существует с тем же значением.

Теперь посмотрим на другой пример.

Новый объект ссылки

Переменные x и y не ссылаются на один и тот же объект, потому что x увеличивается на единицу, x создает новый объект ссылки, а y по-прежнему ссылается на 10.

Преобразование сборщика мусора

Сборщик мусора Python классифицировал объекты с помощью своей генерации. Сборщик мусора Python имеет три поколения. Когда мы определяем новый объект в программе, его жизненный цикл обрабатывается первым поколением сборщика мусора. Если объект используется в другой программе, он будет стимулироваться до следующего поколения. У каждого поколения есть порог.

Сборщик мусора вступает в действие, если превышен порог количества выделений за вычетом числа отмененных.

Мы можем изменить пороговое значение вручную с помощью модуля GC. Этот модуль предоставляет метод get_threshold() для проверки порогового значения другого поколения сборщика мусора. Давайте разберемся в следующем примере.

Пороговое значение для запуска сборщика мусора можно изменить с помощью метода set_threshold().

В приведенном выше примере значение порога увеличилось для всех трех поколений. Это повлияет на частоту запуска сборщика мусора. Программистам не нужно беспокоиться о сборщике мусора, но он играет важную роль в оптимизации среды выполнения Python для целевой системы.

Сборщик мусора Python обрабатывает низкоуровневые детали для разработчика.

Важность выполнения ручной сборки мусора

Как мы обсуждали ранее, интерпретатор Python обрабатывает ссылку на объект, используемый в программе. Он автоматически освобождает память, когда счетчик ссылок становится равным нулю. Это классический подход для подсчета ссылок, если он не работает, когда программа ссылается на циклы. Цикл ссылок происходит, когда один или несколько объектов ссылаются друг на друга. Следовательно, счетчик ссылок никогда не становится нулевым.

Мы создали справочный цикл. Объект list1 ссылается на сам объект list1. Когда функция возвращает объект list1, память для объекта list1 не освобождается. Так что подсчет ссылок не подходит для решения ссылочного цикла. Но мы можем решить эту проблему, изменив сборщик мусора или производительность сборщика мусора.

Для этого мы будем использовать функцию gc.collect() для модуля gc.

Приведенный выше код даст количество собранных и освобожденных объектов.

Метод gc.collect() используется для выполнения сборки мусора по времени. Этот метод вызывается через фиксированный интервал времени для выполнения сборки мусора на основе времени.

При четной сборке мусора функция gc.collect() вызывается после возникновения события. Давайте разберемся в следующем примере.

В приведенном выше коде мы создали объект list1, на который ссылается переменная list. Первый элемент объекта списка ссылается на себя. Счетчик ссылок на объект списка всегда больше нуля, даже если он удален или выходит за рамки программы.

Управление памятью в Python

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

Python использует часть памяти для внутреннего использования и необъектную память. Другая часть памяти используется для объекта Python, такого как int, dict, list и т. д.

CPython содержит распределитель объектов, который выделяет память в области объекта. Распределитель объектов получает вызов каждый раз, когда новому объекту требуется место. Распределитель предназначен для небольшого количества данных, потому что Python не задействует слишком много данных за раз. Он выделяет память, когда это абсолютно необходимо.

Стратегия выделения памяти CPython состоит из трех основных компонентов.

Распространенные способы уменьшить сложность пространства

Мы можем следовать некоторым передовым методам, чтобы уменьшить сложность пространства. Эти методы должны сэкономить достаточно места и сделать программу эффективной. Ниже приведены несколько практик в Python для распределителей памяти.

Мы определяем список на Python; распределитель памяти распределяет память кучи соответственно индексации списка. Предположим, нам нужен подсписок к данному списку, затем мы должны выполнить нарезку списка. Это простой способ получить подсписок из исходного списка. Он подходит для небольшого количества данных, но не подходит для емких данных.

Следовательно, нарезка списка генерирует копии объекта в списке, просто копирует ссылку на них. В результате распределитель памяти Python создает копию объекта и выделяет ее. Поэтому нам нужно избегать разрезания списка.

Лучший способ избежать этого: разработчик должен попытаться использовать отдельную переменную для отслеживания индексов, а не нарезать список.

Разработчик должен попытаться использовать «для элемента в массиве» вместо «для индекса в диапазоне(len(array))» для экономии места и времени. Если программе не нужна индексация элемента списка, не используйте ее.

Конкатенация строк не подходит для экономии места и времени. По возможности, мы должны избегать использования знака «+» для конкатенации строк, потому что строки неизменяемы. Когда мы добавляем новую строку к существующей строке, Python создает новую строку и присваивает ее новому адресу.

Каждая строка требует фиксированного размера памяти в зависимости от символа и его длины. Когда мы меняем строку, ей требуется другой объем памяти и ее необходимо перераспределить.

Мы создали переменную a для ссылки на строковый объект, который является информацией о строковом значении.

Затем мы добавляем новую строку с помощью оператора «+». Python перераспределяет новую строку в памяти в зависимости от ее размера и длины. Предположим, что размер памяти исходной строки равен n байтам, тогда новая строка будет размером m байтов.

Вместо использования конкатенации строк мы можем использовать «.join(iterable_object)» или формат или%. Это оказывает огромное влияние на экономию памяти и времени.

Итераторы очень полезны как для времени, так и для памяти при работе с большим набором данных. Работая с большим набором данных, нам нужна немедленная обработка данных, и мы можем дождаться, пока программа сначала обработает весь набор данных.

В следующем примере мы реализуем итератор, который вызывает специальную функцию генератора. Ключевое слово yield возвращает текущее значение, переходя к следующему значению только на следующей итерации цикла.

  • По возможности используйте встроенную библиотеку

Если мы используем методы, которые уже были предопределены в библиотеке Python, импортируйте соответствующую библиотеку. Это сэкономит много места и времени. Мы также можем создать модуль, чтобы определить функцию и импортировать ее в текущую рабочую программу.

Заключение

Как сохранить данные в Python?

Когда мы работаем над приложениями Python, мы будем иметь дело с объектами Python напрямую, так как все является объектом в Python. Давайте посмотрим на некоторые способы, которыми мы можем легко хранить их!

1. Использование сочинения для хранения объектов Python

Если мы хотим держать вещи простыми, мы можем использовать модуль сортировки, который является частью стандартной библиотеки для сохранения данных в Python.

Мы можем «сортировать» объекты Python в пиловый файл, который мы можем использовать для сохранения данных/загрузки данных.

Поэтому, если у вас есть пользовательский объект, который вам может потребоваться хранить/извлекать, вы можете использовать этот формат:

Если вы запускаете этот скрипт, вы заметите файл под названием data.pickle , который содержит сохраненные данные.

Чтобы снова загрузить один и тот же объект, мы могли бы использовать 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На самом деле для многих начинающих понимание данных является наиболее важным и наиболее подверженным ошибкам. Эта статья использует данные и память для объяснения данных в Python, в том числе:

  • Ссылки и объекты
  • Переменные и неизменные типы данных
  • Передать по значению и передать по значению
  • Глубокая и мелкая копия

(функция id:Вы можете проверить идентичность объекта через встроенную функцию Python id (). Эта так называемая идентичность на самом делеАдрес памяти объекта)


Сначала ссылки и объекты:Отношения между ссылками и объектами:


Объект:Когда создается объект данных, значение объекта сохраняется в памяти, и этим значением является сам объект; (строковый объект: "wupeiqi")
Quote:Объекты хранятся в памяти. Если вы хотите использовать значение объекта снаружи, вам нужно использовать ссылку, которая является «name1», «name2». В памяти будет храниться количество ссылок на объект. Когда количество ссылок на объект равно 0, объект будет переработан.

Переменные типы данных и неизменные типы данных
1. Классификация данных:

  • Типы переменных данных: список и словарь
  • Неизменяемые типы данных: целое число int, число с плавающей запятой, строка и кортеж

Переменная здесь неизменна,Можно ли изменить значение в памяти, Если это неизменяемый тип, он должен находиться в памяти при работе с самим объектом.Подать заявку на новую область(Потому что старая область неизменна). Если это изменчивый тип, при работе с объектом,Не нужно подавать заявку на память в другом месте, просто нужно применять непрерывно после этого объекта(+/-) достаточно, то есть его адрес останется прежним, но область станет длиннее или короче.

(1) Неизменяемый тип данных в Python не позволяет изменять значение переменной. Если значение переменной изменяется, это эквивалентно созданию нового объекта. Для объекта с таким же значением в памяти имеется только один объект. Будет подсчет ссылок, чтобы записать, сколько переменных ссылаются на этот объект;
(2) Тип данных переменной позволяет изменять значение переменной, то есть, если вы выполняете операцию добавления, + = и т. д. с переменной, вы изменяете только значение переменной без изменения Когда вы создаете новый объект, адрес переменной, на которую ссылается переменная, не изменится, но для разных объектов с одинаковым значением в памяти будут разные объекты, то есть каждый объект имеет свой собственный адрес, который эквивалентен одному и тому же в памяти для одного и того же объекта. Объект значения содержит несколько копий,Здесь нет подсчета ссылок, это реальный объект。”

2. Неизменяемые типы данных:Неизменные средстваЦенность самого объекта неизменна(Когда вы создаете целочисленный объект a = 1, используйте для ссылки на него объект. Объект 1 в памяти не изменяется. Когда вы выполняете a = 2, вы просто воссоздаете объект 2 и используете для него ссылку a. Если 1 объект не имеет другого Рекомендации будут переработаны)


Объяснение:здесьНеизменным, вы можете понять, что значение по адресу, указанному в x, не может быть измененоТаким образом, значение по адресу 31106520 всегда равно 1. До тех пор, пока оно не будет собирать мусор. Если вы хотите назначить x для 2, вы можете изменить только адрес, на который ссылается x, с 31106520 на 31106508, что эквивалентно x = 2 Присвоение создает другой объект, то есть объект 2, а затем x, y и z все ссылаются на этот объект, поэтому тип данных int является неизменным. Если вы хотите снова назначить переменную типа int, она эквивалентна другой в памяти. Новый объект создан, и он больше не является предыдущим объектом. Процесс вышеуказанной программы можно увидеть на рисунке ниже.

3. Переменные объекты:Переменные средстваЗначение самого объекта является изменчивым(Список, значения объекта dict фактически ссылаются на другие объекты, При изменении значения объекта оно фактически ссылается на другой объект)


Объяснение: (1) Выполните операцию a = [1, 2, 3] дважды, и значения адресов, на которые ссылается a, отличаются, то есть фактически создаются два разных объекта, что, очевидно, отличается от неизменяемых данных. Тип, поэтому для переменного типа данных объекты с одинаковым значением являются разными объектами, то есть несколько объектов с одинаковым значением хранятся в памяти с разными значениями адреса.
(2) Мы добавляем в список операции a.append (4) и a + = [2] и обнаруживаем, что эти две операции делают значение объекта, на который ссылается a, указанным выше. Окончательный результат, но адрес, на который ссылается a, по-прежнему 41575088, что означает, что операция, выполняемая над a, не изменит значения адреса, на который ссылается a, но расширит новый адрес после адреса и изменит значение, сохраненное в адресе.Таким образом, тип данных переменной означает, что при работе с переменной ее значение является переменным. Изменение значения не приведет к созданию нового объекта, то есть адрес не изменится, но содержимое адреса изменится или адрес изменится. Был расширен.Следующий рисунок иллюстрирует этот процесс, и его можно ясно увидеть.

В-третьих, передать по значению и передать по значению:Изменяемые объекты передаются по ссылке, неизменные объекты передаются по значению. (Передача значения функции)
1. Передайте по ссылке:При передаче списка или словаря, если вы меняете ссылочное значение, вы изменяете исходный объект.

2, передача значения:Когда вы передаете неизменный объект, если вы изменяете значение ссылки, вы просто создаете другой объект, и исходный объект не изменяется.

В-четвертых, глубокая и мелкая копия:
copy.copy () мелкая копия; copy.deepcopy () глубокая копия, Мелкая копия - это вновь созданный тип того же типа, что и исходный объект.Но его содержание является ссылкой на оригинальный элемент объекта, Эта копияСам объект новый, но содержание не。При копировании объектов типа последовательности (list \ tuple) по умолчанию используется мелкая копия.


1. Копия задания:
, просто создайте переменную, которая указывает на исходный адрес памяти: n4 = n3 = n2 = n1 = "123 /’ Wu ’»

2, мелкая копия:Создать только первый слой данных в памяти


3, глубокая копия:Создайте копию всех данных в памяти (исключая последний слой, то есть: оптимизацию строк и чисел внутри Python)

Читайте также: