2009-02-17 51 views
0

我有一些嚴重依賴於MySQL的軟件,它是用python編寫的,沒有任何類定義。出於性能原因,並且因爲數據庫實際上只是用於存儲和檢索大量數據,所以我想將其轉換爲面向對象的Python腳本,根本不使用數據庫。將數據庫驅動的(非OO)python腳本轉換爲非數據庫驅動的OO腳本

所以我的計劃是將數據庫表導出到一組文件中(不是很多 - 這是一個非常簡單的數據庫;它的重要性在於它有很多行,但只有幾個表,每個表都有隻有兩列或三列)。

然後我打算讀取數據,並有一組函數提供對數據的訪問和操作。

我的問題是這樣的:

有轉換一組數據庫表的類和對象的優選方式?例如,如果我有一個包含水果的表,其中每個水果都有一個ID和一個名稱,我是否會有一個包含「水果」對象列表的「CollectionOfFruit」類,或者我是否只有一個「CollectionOfFruit」類其中包含元組列表?或者我只是有一個水果對象的列表?

我不想添加任何額外的框架,因爲我希望這個代碼很容易轉移到不同的機器上。所以我真的只是尋找關於如何表示可能更自然地存儲在數據庫表中的數據的一般性建議,在Python中的對象中。

另外,是否有一本好書應該閱讀,這將指向我在這個正確的方向嗎?

回答

5

如果數據是天作之合數據庫表(「矩形數據「),爲什麼不把它轉換成sqlite?它是可移植的 - 只需要一個文件來移動數據庫,並且sqlite可以在任何有python的地方使用(無論如何2.5)。

+0

您甚至不必將其加載到文件中。你可以把它全部加載到內存中。 – 2009-02-17 21:46:19

1

對此,沒有「一刀切」的答案 - 它將取決於數據以及它在應用程序中的使用方式。如果數據和用法足夠簡單,您可能希望將您的水果存儲在一個字典中,其中id爲key,其餘數據爲元組。或不。這完全取決於。如果這裏有一個指導原則,那就是提取應用程序的基本需求,然後根據這些需求編寫代碼。

1

你可以擁有一個帶有id和name實例變量的水果類。以及一個讀取/寫入文件信息的功能,也可能是一個類變量,用於跟蹤創建的水果(對象)的數量。

2

通常,您希望您的對象完全匹配您的「真實世界實體」。

由於您是從數據庫開始的,數據庫並不總是具有真實世界的保真度。一些數據庫設計簡直太糟糕了。

如果您的數據庫有合理的水果模型,那就是您開始的地方。先把它弄好。

「集合」可能 - 也可能不 - 是一種人爲構造,它是解算算法的一部分,並不是問題的適當部分。通常集合都是問題的一部分,你也應該設計這些類。

然而,其他時候,集合是使用數據庫的工具,並且只需要一個簡單的Python列表。

還有一些其他時候,集合實際上是從某個唯一鍵值到實體的正確映射,在這種情況下,它是一個Python字典。

有時,集合是從一些非唯一鍵值到某些實體集合的正確映射,在這種情況下,它是一個Python collections.defaultdict(list)

從基本的,真實世界的實體開始。那些獲得類定義。

集合可能使用內置的Python集合或可能需要自己的類。

1

在簡單情況下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

另一種方法是使用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

這裏有幾點要考慮。如果您的數據很大,則將其全部存入內存可能會造成浪費。如果您需要隨機訪問,而不僅僅是順序訪問數據,那麼您每次必須至多掃描整個文件,或者將該表讀入索引內存結構(如字典)。列表仍然需要某種掃描(直接迭代或二進制搜索,如果排序)。有了這個說法,如果你不需要數據庫的某些功能,那麼就不要使用它,但是如果你認爲MySQL太重了,那麼從前面的Sqlite建議+1。它爲您提供了使用數據庫時不需要併發開銷的大部分功能。

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對象。