Создание списка словарей с помощью cx_Oracle

Я использовал следующую функцию, чтобы сделать «более читаемый» (предположительно) формат для извлечения данных из 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

Затем я бы использовал такую ​​​​функцию:

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.

Хотя это, кажется, работает довольно хорошо при различных уровнях стресса, мне интересно, есть ли более эффективный или «питоновский» способ сделать это.


person Nitzle    schedule 04.05.2012    source источник


Ответы (6)


Есть и другие улучшения, которые нужно сделать, но это действительно бросилось мне в глаза:

    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)]

Использование index в подобных ситуациях не только неэффективно, но и чревато ошибками, по крайней мере, в ситуациях, когда один и тот же элемент может встречаться в списке дважды. Вместо этого используйте enumerate:

    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]

Но на самом деле это мелкая картошка. Вот гораздо более компактная версия этой функции:

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

Дай мне знать, если это работает.

person senderle    schedule 04.05.2012
comment
Что делать, если нужно выполнить некоторую постобработку элементов каждой строки. Тогда это не сработает -› [dict(zip(columns, row)) для строки в курсоре] - person ramu; 18.09.2015
comment
@ramu, для меня это звучит как новый вопрос. Если кто-то еще не задал его здесь, возможно, вам следует. - person senderle; 18.09.2015
comment
Легенда! Спасибо - person Tony Sepia; 01.12.2017

Для чистого способа избежать использования памяти при предварительном сбросе всего в списке вы можете обернуть курсор в функцию генератора:

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))

Затем используйте следующим образом: строки из курсора преобразуются в словари при итерации:

for row in rows_as_dicts(cursor):
    item1 = row["col1"]
    item2 = row["col2"]
person Josh Werts    schedule 29.08.2013
comment
Это, вероятно, хорошо для больших наборов результатов, но я обнаружил, что он менее эффективен, чем ответ @senderle для относительно небольших наборов результатов. - person bspkrs; 19.06.2015
comment
@bspkrs Спасибо - я это видел. Есть ли у вас какие-либо цифры фактической разницы в производительности, которую вы видели? - person Josh Werts; 19.06.2015
comment
Python также позволяет вам встраивать генераторы: for row in (i[0] for i in cursor.description):. Нет необходимости в отдельной функции. - person jpmc26; 12.08.2017
comment
@ jpmc26 Это отличное предложение - я обычно забываю об этом! - person Josh Werts; 14.08.2017

Вы не должны использовать dict для больших наборов результатов, потому что использование памяти будет огромным. Я часто использую cx_Oracle, и отсутствие хорошего словарного курсора беспокоило меня достаточно, чтобы написать для него модуль. Мне также нужно подключить Python к множеству разных баз данных, поэтому я сделал это так, чтобы вы могли использовать его с любым коннектором DB API 2.

Это на PyPi СУБД — базы данных стали проще

>>> 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']
person Scott Bailey    schedule 08.08.2013

Предположим, что курсор «Курсор» уже определен и готовится к работе:

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

тогда вы можете просто пойти:

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

Не так чисто и гладко, как если бы система справилась сама, но не ужасно.

person The Nate    schedule 05.10.2016

Создать словарь

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

Чтобы получить доступ:

for result in cur
    print (result[cols['COL_NAME']])
person jdex    schedule 24.01.2017

У меня лучше:

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)
person YellowTree    schedule 26.05.2017