2008-09-22 85 views
3

我正在編寫一個簡單的Python Web應用程序,它由多個爲iPhone格式化的業務數據頁組成。我很喜歡編程Python,但我對Python的「成語」並不是很熟悉,特別是在類和對象方面。 Python的面向對象設計與我所使用的其他語言有所不同。所以,儘管我的應用程序正在運行,但我很好奇是否有更好的方法來實現我的目標。在Python中操作數據庫結果集的最佳實踐?

細節:通常如何在Python中實現request-transform-render數據庫工作流?目前,我使用pyodbc來獲取數據,將結果複製到對象的屬性上,執行一些計算並使用這些對象的列表進行合併,然後從對象列表中呈現輸出。 (下面的示例代碼,SQL查詢編輯。)這是否理智?有沒有更好的辦法?在我對Python的相對無知中有什麼具體的「陷阱」嗎?我特別關心如何使用空的「Record」類實現行列表。

class Record(object): 
    pass 

def calculate_pnl(records, node_prices): 
    for record in records: 
     try: 
      # fill RT and DA prices from the hash retrieved above 
      if hasattr(record, 'sink') and record.sink: 
       record.da = node_prices[record.sink][0] - node_prices[record.id][0] 
       record.rt = node_prices[record.sink][1] - node_prices[record.id][1] 
      else: 
       record.da = node_prices[record.id][0] 
       record.rt = node_prices[record.id][1] 

      # calculate dependent values: RT-DA and PNL 
      record.rtda = record.rt - record.da 
      record.pnl = record.rtda * record.mw 
     except: 
      print sys.exc_info() 

def map_rows(cursor, mappings, callback=None): 
    records = [] 
    for row in cursor: 
     record = Record() 
     for field, attr in mappings.iteritems(): 
      setattr(record, attr, getattr(row, field, None)) 
     if not callback or callback(record): 
      records.append(record) 

    return records 

def get_positions(cursor): 
    # get the latest position time 
    cursor.execute("SELECT latest data time") 
    time = cursor.fetchone().time 
    hour = eelib.util.get_hour_ending(time) 

    # fetch the current positions 
    cursor.execute("SELECT stuff FROM atable", (hour)) 

    # read the rows 
    nodes = {} 
    def record_callback(record): 
     if abs(record.mw) > 0: 
      if record.id: nodes[record.id] = None 
      return True 
     else: 
      return False 
    records = util.map_rows(cursor, { 
     'id': 'id', 
     'name': 'name', 
     'mw': 'mw' 
    }, record_callback) 

    # query prices 
    for node_id in nodes: 
     # RT price 
     row = cursor.execute("SELECT price WHERE ? ? ?", (node_id, time, time)).fetchone() 
     rt5 = row.lmp if row else None 

     # DA price 
     row = cursor.execute("SELECT price WHERE ? ? ?", (node_id, hour, hour)).fetchone() 
     da = row.da_lmp if row else None 

     # update the hash value 
     nodes[node_id] = (da, rt5) 

    # calculate the position pricing 
    calculate_pnl(records, nodes) 

    # sort 
    records.sort(key=lambda r: r.name) 

    # return the records 
    return records 

回答

1

空記錄類和(通常)適用於單個記錄的自由浮動函數暗示您沒有正確設計類。

class Record(object): 
    """Assuming rtda and pnl must exist.""" 
    def __init__(self): 
     self.da= 0 
     self.rt= 0 
     self.rtda= 0 # or whatever 
     self.pnl= None # 
     self.sink = None # Not clear what this is 
    def setPnl(self, node_prices): 
     # fill RT and DA prices from the hash retrieved above 
     # calculate dependent values: RT-DA and PNL 

現在,您的calculate_pnl(records, node_prices)更簡單,並正確使用該對象。

def calculate_pnl(records, node_prices): 
    for record in records: 
     record.setPnl(node_prices) 

重點不在於以微小的方式重構代碼。

關鍵是這樣的:A類封裝責任

是的,一個空洞的類通常是一個問題。這意味着責任分散在別處。

類似的分析適用於收集記錄。這不僅僅是一個簡單的列表,因爲這個集合 - 作爲一個整體 - 具有它所執行的操作。

「請求變換渲染」不太正確。你有一個模型(記錄類)。模型的實例被構建(可能是由於Request).Model對象負責其自己的狀態轉換和更新。也許他們會被一些檢查其狀態的對象顯示(或呈現)。

這就是「變換」步驟,通常會違反良好的設計,將責任推到各處。 「變換」是非對象設計的延續,其中責任是一個模糊的概念。

1

您是否考慮過使用ORM? SQLAlchemy非常好,Elixir使它美麗。它可以真正減少處理數據庫所需的樣板代碼量。此外,很多提到的陷阱已經出現,SQLAlchemy開發人員處理了它們。

+0

我不認爲ORM是合適的。我不希望寫入數據庫 - 這完全是一個數據顯示項目。並且編寫查詢不是問題(實際上,我打算簡化上面發佈的第一個草稿代碼,以消除查詢在循環問題)。 – 2008-09-22 19:33:50

-2

由於性能問題,對iPhone應用使用ORM可能不是個好主意,所以您希望代碼儘可能快。所以你不能避免樣板代碼。如果你正在考慮一個ORM,除了SQLAlchemy,我會推薦Storm。

+0

他說「格式化爲iPhone」,我猜想這是一個網頁。 ORM將在服務器端。我知道ORM增加了一些開銷,但手機網絡將成爲真正的延遲誘導者。 – alif 2008-09-22 20:01:02

+0

ORM在Python中。可以在客戶端上。 ORM將純SQL發送到服務器。 – 2008-09-22 22:11:32

+0

就像我在我的問題的第一句話中所說的,這是一個網絡應用程序。 Python代碼位於服務器上。另外,我對ORM並不感興趣,因爲我只有一些設置只讀查詢來實現。 – 2008-09-22 22:16:05

0

取決於您想要處理多少數據,您可能不需要填充中間對象。遊標的標題數據結構可以讓你獲得列名 - 有一點自省會讓你爲該行創建一個包含col-name:value對的字典。 您可以將字典傳遞給%運算符。 odbc模塊的文檔將解釋如何獲取列元數據。

這段代碼以這種方式顯示%操作符的應用程序。

>>> a={'col1': 'foo', 'col2': 'bar', 'col3': 'wibble'} 
>>> 'Col1=%(col1)s, Col2=%(col2)s, Col3=%(col3)s' % a 
'Col1=foo, Col2=bar, Col3=wibble' 
>>>