将数据库驱动(非OO)python脚本转换为非数据库驱动的OO脚本
我有一些严重依赖MySQL的软件,是用python编写的,没有任何类定义。出于性能原因,并且由于数据库实际上只是用于存储和检索大量数据,我想将其转换为一个完全不使用数据库的面向对象python脚本 所以我的计划是将数据库表导出到一组文件中(不是很多——这是一个非常简单的数据库;它很大,因为它有很多行,但只有几个表,每个表只有两到三列) 然后我计划在中读取数据,并拥有一组函数,这些函数提供对数据的访问和操作 我的问题是: 是否有将一组数据库表转换为类和对象的首选方法?例如,如果我有一个包含水果的表,其中每个水果都有一个id和一个名称,我会有一个包含“水果”对象列表的“CollectionOfFruit”类,还是只有一个包含元组列表的“CollectionOfFruit”类?或者我只需要一份水果物品的清单 我不想添加任何额外的框架,因为我希望这些代码能够轻松地传输到不同的机器上。所以我真的只是在寻找关于如何表示可能更自然地存储在Python中的数据库表和对象中的数据的一般建议将数据库驱动(非OO)python脚本转换为非数据库驱动的OO脚本,python,object,Python,Object,我有一些严重依赖MySQL的软件,是用python编写的,没有任何类定义。出于性能原因,并且由于数据库实际上只是用于存储和检索大量数据,我想将其转换为一个完全不使用数据库的面向对象python脚本 所以我的计划是将数据库表导出到一组文件中(不是很多——这是一个非常简单的数据库;它很大,因为它有很多行,但只有几个表,每个表只有两到三列) 然后我计划在中读取数据,并拥有一组函数,这些函数提供对数据的访问和操作 我的问题是: 是否有将一组数据库表转换为类和对象的首选方法?例如,如果我有一个包含水果的表
或者,我应该读一本好书,为我指明正确的方向吗?对此没有“一刀切”的答案——这在很大程度上取决于数据以及它在应用程序中的使用方式。如果数据和用法足够简单,您可能希望将水果存储在dict中,id作为键,其余数据作为元组。或者不是。这完全取决于情况。如果有一个指导原则的话,那就是提取应用程序的底层需求,然后根据这些需求编写代码。您可以拥有一个带有id和name实例变量的水果类。还有一个从文件中读取/写入信息的函数,也许还有一个类变量来跟踪创建的水果(对象)的数量。通常,您希望对象与“真实世界实体”完全匹配 因为您是从数据库开始的,所以数据库也不总是具有真实世界的保真度。有些数据库设计简直糟透了 如果你的数据库有合理的水果模型,那就是你的起点。先把它弄对 “集合”可能是——也可能不是——一个人工构造,它是解决方案算法的一部分,而不是问题的真正部分。通常,集合是问题的一部分,您也应该设计这些类 然而,在其他情况下,集合是使用数据库的产物,您只需要一个简单的Python列表 还有一些时候,集合实际上是从某个唯一键值到实体的正确映射,在这种情况下,它是一个Python字典 有时,集合是从某个非唯一键值到某个实体集合的正确映射,在这种情况下,它是Python
collections.defaultdict(list)
从基本的、真实的实体开始。它们得到类定义
集合可以使用内置的Python集合,也可以需要自己的类。在简单的情况下,让我们开始:
>>> from collections import namedtuple
>>> Fruit = namedtuple("Fruit", "name weight color")
>>> fruits = [Fruit(*row) for row in cursor.execute('select * from fruits')]
水果
相当于以下类别:
>>> 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))
如果数据自然适合数据库表(“矩形数据”),为什么不将其转换为sqlite?它是可移植的——只需一个文件就可以移动数据库,而sqlite可以在任何有python的地方使用(无论如何,2.5及以上版本)。另一种方法是使用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])
它会自动存储在数据库中。您只需从根对象访问“collection”即可再次找到它:
print root.collection.fruit
您还可以像往常一样从例如水果派生子类
提供更多信息的有用链接:
这样,您仍然可以使用Python对象的全部功能,并且不需要通过ORM来序列化某些东西,但是您仍然有一种简单的方法来存储数据。
这里有几个要点供您考虑。如果您的数据很大,将其全部读入内存可能是浪费。如果需要对数据进行随机访问,而不仅仅是顺序访问,那么每次最多只能扫描整个文件,或者将该表读入索引内存结构(如字典)。列表仍然需要某种扫描(如果排序,则直接迭代或二进制搜索)。话虽如此,如果您不需要DB的某些功能,那么就不要使用它,但是如果您只是认为MySQL太重,那么在前面的Sqlite建议中+1。它为您提供了使用数据库时所需的大部分功能,而无需并发开销。
从对象类抽象持久性。将所有持久性逻辑放在适配器类中,并将适配器分配给对象类。比如: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类将完全不受影响。您甚至不必将其加载到文件中。您可以将其全部加载到内存中。