2012-05-04 14 views
16

Ho utilizzato la seguente funzione per creare un formato "più leggibile" (presumibilmente) per il recupero dei dati da Oracle. Ecco la funzione:Creazione di un elenco di dizionari con cx_Oracle

def rows_to_dict_list(cursor): 
    """ 
    Create a list, each item contains a dictionary outlined like so: 
    { "col1_name" : col1_data } 
    Each item in the list is technically one row of data with named columns, 
    represented as a dictionary object 
    For example: 
    list = [ 
     {"col1":1234567, "col2":1234, "col3":123456, "col4":BLAH}, 
     {"col1":7654321, "col2":1234, "col3":123456, "col4":BLAH} 
    ] 
    """ 

    # Get all the column names of the query. 
    # Each column name corresponds to the row index 
    # 
    # cursor.description returns a list of tuples, 
    # with the 0th item in the tuple being the actual column name. 
    # everything after i[0] is just misc Oracle info (e.g. datatype, size) 
    columns = [i[0] for i in cursor.description] 

    new_list = [] 
    for row in cursor: 
     row_dict = dict() 
     for col in columns: 
      # Create a new dictionary with field names as the key, 
      # row data as the value. 
      # 
      # Then add this dictionary to the new_list 
      row_dict[col] = row[columns.index(col)] 

     new_list.append(row_dict) 
    return new_list 

Vorrei quindi utilizzare la funzione in questo modo:

sql = "Some kind of SQL statement" 
curs.execute(sql) 
data = rows_to_dict_list(curs) 
# 
for row in data: 
    item1 = row["col1"] 
    item2 = row["col2"] 
    # Do stuff with item1, item2, etc... 
    # You don't necessarily have to assign them to variables, 
    # but you get the idea. 

Anche se questo sembra a svolgere abbastanza bene sotto i livelli di stress varia, mi chiedo se c'è una più efficiente o modo "pitonico" per farlo.

risposta

24

Non ci sono altri miglioramenti da fare, ma questo in realtà è saltato fuori a me:

for col in columns: 
     # Create a new dictionary with field names as the key, 
     # row data as the value. 
     # 
     # Then add this dictionary to the new_list 
     row_dict[col] = row[columns.index(col)] 

Oltre ad essere inefficiente, utilizzando index in situazioni come questa è soggetto ad errori, almeno nelle situazioni in cui la stessa l'elemento può apparire due volte in un elenco. Utilizzare enumerate invece:

for i, col in enumerate(columns): 
     # Create a new dictionary with field names as the key, 
     # row data as the value. 
     # 
     # Then add this dictionary to the new_list 
     row_dict[col] = row[i] 

Ma questo è patate piccole, davvero. Ecco una versione molto più compatto di questa funzione:

def rows_to_dict_list(cursor): 
    columns = [i[0] for i in cursor.description] 
    return [dict(zip(columns, row)) for row in cursor] 

fatemi sapere se funziona.

+0

funziona come un fascino. Grazie! – Nitzle

+0

Cosa succede se è necessario eseguire qualche post elaborazione sugli elementi di ciascuna riga. Quindi questo non funzionerebbe -> [dict (zip (colonne, riga)) per riga nel cursore] – ramu

+0

@ramu, mi sembra una nuova domanda. Se qualcuno non l'ha già chiesto qui, forse dovresti. – senderle

3

Non si dovrebbe usare il dict per i set di grandi risultati perché l'utilizzo della memoria sarà enorme. Io uso molto cx_Oracle e non ho un buon cursore del dizionario che mi ha infastidito abbastanza da scrivere un modulo per questo. Devo anche collegare Python a molti database diversi, così l'ho fatto in un modo che puoi usare con qualsiasi connettore DB API 2.

E 'su Cheese Shop DBMS - DataBases Made Simpler

>>> import dbms 
>>> db = dbms.OraConnect('myUser', 'myPass', 'myInstance') 
>>> cur = db.cursor() 
>>> cur.execute('SELECT * FROM people WHERE id = :id', {'id': 1123}) 
>>> row = cur.fetchone() 
>>> row['last_name'] 
Bailey 
>>> row.last_name 
Bailey 
>>> row[3] 
Bailey 
>>> row[0:4] 
[1123, 'Scott', 'R', 'Bailey'] 
8

Per un modo pulito per evitare l'utilizzo della memoria di pratiche di dumping tutto in una lista in anticipo, si potrebbe avvolgere il cursore in una funzione di generatore:

def rows_as_dicts(cursor): 
    """ returns cx_Oracle rows as dicts """ 
    colnames = [i[0] for i in cursor.description] 
    for row in cursor: 
     yield dict(zip(colnames, row)) 

Quindi utilizzare come segue: le righe del cursore vengono convertite in virgole durante l'iterazione:

for row in rows_as_dicts(cursor): 
    item1 = row["col1"] 
    item2 = row["col2"] 
+0

Questo è probabilmente un bene per i set di risultati di grandi dimensioni, ma ho trovato meno performante della risposta di @ senderle per set di risultati relativamente piccoli. – bspkrs

+0

@bspkrs Grazie - l'ho visto. Hai numeri sulla differenza di prestazioni effettiva che hai visto? –

+0

Python consente anche ai generatori in linea: 'per riga in (i [0] per i in cursor.description):'. Non c'è bisogno di una funzione separata. – jpmc26

0

Assumere cursore "Cursore" è già definito e impaziente di cominciare:

byCol = {cl:i for i,(cl,type, a, b, c,d,e) in enumerate(Cursor.description)}

allora si può solo andare:

for row in Cursor: column_of_interest = row[byCol["COLUMN_NAME_OF_INTEREST"]]

Non come pulita e liscia come se il sistema ha gestito stesso, ma non è orribile.

0

Creare un dict

cols=dict() 
for col, desc in enumerate(cur.description): 
    cols[desc[0]] = col 

Per accedere:

for result in cur 
    print (result[cols['COL_NAME']]) 
0

ho uno migliore:

import cx_Oracle 

def makedict(cursor): 
"""Convert cx_oracle query result to be a dictionary 
""" 
cols = [d[0] for d in cursor.description] 

def createrow(*args): 
    return dict(zip(cols, args)) 

return createrow 

db = cx_Oracle.connect('user', 'pw', 'host') 
cursor = db.cursor() 
rs = cursor.execute('SELECT * FROM Tablename') 
cursor.rowfactory = makedict(cursor) 
Problemi correlati