python - recorrer - Hacer una lista de diccionarios con cx_Oracle
lista de diccionarios python (6)
Crear un dict
cols=dict()
for col, desc in enumerate(cur.description):
cols[desc[0]] = col
Acceder:
for result in cur
print (result[cols[''COL_NAME'']])
He estado usando la siguiente función para hacer un formato "más legible" (supuestamente) para obtener datos de Oracle. Aquí está la función:
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
Entonces usaría la función así:
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.
Si bien esto parece funcionar bastante bien bajo diferentes niveles de estrés, me pregunto si hay una forma más eficiente o "pitónica" de hacer esto.
Hay otras mejoras que hacer, pero esto realmente me llamó la atención:
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)]
Además de ser ineficiente, el uso del index
en situaciones como esta es propenso a errores, al menos en situaciones donde el mismo elemento puede aparecer dos veces en una lista. Utilice enumerate
lugar:
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]
Pero eso es papas pequeñas, de verdad. Aquí hay una versión mucho más compacta de esta función:
def rows_to_dict_list(cursor):
columns = [i[0] for i in cursor.description]
return [dict(zip(columns, row)) for row in cursor]
Déjame saber si eso funciona.
No debe usar dict para grandes conjuntos de resultados porque el uso de la memoria será enorme. Uso mucho cx_Oracle y no tengo un buen diccionario que me haya molestado lo suficiente como para escribir un módulo para él. También tengo que conectar Python a muchas bases de datos diferentes, así que lo hice de una manera que puede usar con cualquier conector DB API 2.
Está en PyPi DBMS - Bases de datos simplificadas
>>> 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'']
Para obtener una manera limpia de evitar el uso de la memoria de descargar todo en una lista por adelantado, puede ajustar el cursor en una función de generador:
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))
Luego use de la siguiente manera: las filas del cursor se convierten a dictados mientras se repite:
for row in rows_as_dicts(cursor):
item1 = row["col1"]
item2 = row["col2"]
Supongamos que el cursor "Cursor" ya está definido y listo para ir:
byCol = {cl:i for i,(cl,type, a, b, c,d,e) in enumerate(Cursor.description)}
entonces solo puedes ir
for row in Cursor: column_of_interest = row[byCol["COLUMN_NAME_OF_INTEREST"]]
No tan limpio y suave como si el sistema lo manejara solo, pero no horrible.
Tengo una mejor
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)