Преобразование сценария Python, управляемого базой данных (не OO), в сценарий OO, не управляемый базой данных - PullRequest
0 голосов
/ 17 февраля 2009

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

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

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

Мой вопрос такой:

Есть ли предпочтительный способ преобразования набора таблиц базы данных в классы и объекты? Например, если у меня есть таблица с фруктами, где у каждого фрукта есть идентификатор и имя, у меня будет класс «CollectionOfFruit», который содержит список объектов «Фрукты», или у меня будет просто класс «CollectionOfFruit» который содержит список кортежей? Или у меня просто есть список объектов Fruit?

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

В качестве альтернативы, есть ли хорошая книга, которую я должен прочитать, которая укажет мне правильное направление в этом направлении?

Ответы [ 8 ]

5 голосов
/ 17 февраля 2009

Если данные естественным образом подходят для таблиц базы данных («прямоугольные данные»), почему бы не преобразовать их в sqlite? Он переносим - всего один файл для перемещения базы данных, и sqlite доступен везде, где у вас есть python (2.5 и выше).

2 голосов
/ 17 февраля 2009

Как правило, вы хотите, чтобы ваши объекты полностью соответствовали вашим "сущностям реального мира".

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

Если в вашей базе данных есть разумные модели для Fruit, то с этого и начинайте. Получите это право первым.

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

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

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

И иногда коллекция представляет собой правильное отображение некоторого неуникального значения ключа на некоторую коллекцию сущностей, в этом случае это Python collections.defaultdict(list).

Начните с фундаментальных, похожих на реальный мир сущностей. Те получают определения классов.

Коллекции могут использовать встроенные коллекции Python или могут требовать своих собственных классов.

1 голос
/ 18 февраля 2009

Абстрактное постоянство от класса объекта. Поместите всю логику персистентности в класс адаптера и назначьте адаптер классу объекта. Что-то вроде:

class Fruit(Object):

   @classmethod
   def get(cls, id):
      return cls.adapter.get(id)

   def put(self):
      cls.adapter.put(self)

   def __init__(self, id, name, weight, color):
      self.id = id
      self.name = name
      self.weight = weight
      self.color = color


 class FruitAdapter(Object):

    def get(id):
       # retrieve attributes from persistent storage here
       return Fruit(id, name, weight, color)

    def put(fruit):
       # insert/update fruit in persistent storage here

 Fruit.adapter = FruitAdapter()
 f = Fruit.get(1)
 f.name = "lemon"
 f.put()
 # and so on...

Теперь вы можете создавать различные объекты FruitAdapter, которые взаимодействуют с любым сохраняемым форматом сохранения (база данных, плоский файл, коллекция в памяти и т. Д.), И базовый класс Fruit не будет затронут.

1 голос
/ 18 февраля 2009

Вот пара моментов, которые вы должны рассмотреть. Если ваши данные большие, чтение их в память может быть расточительным. Если вам нужен произвольный доступ, а не только последовательный доступ к вашим данным, вам придется каждый раз сканировать максимум весь файл или считывать эту таблицу в индексированную структуру памяти, такую ​​как словарь. Список все еще требует некоторого вида сканирования (прямая итерация или бинарный поиск, если отсортирован). С учетом вышесказанного, если вам не требуются некоторые функции БД, не используйте их, но если вы просто считаете, что MySQL слишком тяжел, тогда +1 по предложению Sqlite из предыдущего. Он предоставляет вам большинство функций, которые вы хотели бы использовать при использовании базы данных без накладных расходов на параллелизм.

1 голос
/ 17 февраля 2009

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

Тогда класс может выглядеть так:

class Collection(persistent.Persistent):

  def __init__(self, fruit = []):
      self.fruit = fruit

class Fruit(peristent.Persistent):

  def __init__(self, name):
      self.name = name

Предполагая, что у вас есть корневой объект, который вы можете сделать:

fruit = Fruit("apple")
root.collection = Collection([fruit])

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

print root.collection.fruit

Вы также можете получить подклассы, например, из Фрукты как обычно.

Полезные ссылки с дополнительной информацией:

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

1 голос
/ 17 февраля 2009

В простом случае namedtuples Позвольте начать:

>>> from collections import namedtuple
>>> Fruit = namedtuple("Fruit", "name weight color")
>>> fruits = [Fruit(*row) for row in cursor.execute('select * from fruits')]

Fruit эквивалентно следующему классу:

>>> Fruit = namedtuple("Fruit", "name weight color", verbose=True)
class Fruit(tuple):
        'Fruit(name, weight, color)'

        __slots__ = ()

        _fields = ('name', 'weight', 'color')

        def __new__(cls, name, weight, color):
            return tuple.__new__(cls, (name, weight, color))

        @classmethod
        def _make(cls, iterable, new=tuple.__new__, len=len):
            'Make a new Fruit object from a sequence or iterable'
            result = new(cls, iterable)
            if len(result) != 3:
                raise TypeError('Expected 3 arguments, got %d' % len(result))
            return result

        def __repr__(self):
            return 'Fruit(name=%r, weight=%r, color=%r)' % self

        def _asdict(t):
            'Return a new dict which maps field names to their values'
            return {'name': t[0], 'weight': t[1], 'color': t[2]}

        def _replace(self, **kwds):
            'Return a new Fruit object replacing specified fields with new values'
            result = self._make(map(kwds.pop, ('name', 'weight', 'color'), self))
            if kwds:
                raise ValueError('Got unexpected field names: %r' % kwds.keys())

            return result

        def __getnewargs__(self):
            return tuple(self)

        name = property(itemgetter(0))
        weight = property(itemgetter(1))
        color = property(itemgetter(2))
1 голос
/ 17 февраля 2009

у вас может быть фруктовый класс с переменными экземпляра id и name. и функция для чтения / записи информации из файла и, возможно, переменная класса для отслеживания количества созданных фруктов (объектов)

1 голос
/ 17 февраля 2009

Для этого не существует ответа «один размер подходит всем» - он будет во многом зависеть от данных и от того, как они используются в приложении. Если данные и использование достаточно просты, возможно, вы захотите сохранить свои фрукты в формате с идентификатором в качестве ключа, а остальные данные в виде кортежей. Или нет. Это полностью зависит. Если есть руководящий принцип, то он должен извлечь основные требования приложения, а затем написать код в соответствии с этими требованиями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...