2012-02-28 6 views
49

Я использую ORM SQL алхимии, и я нашел, когда я вернусь в одну колонке, я получаю результаты, как так:SQL Алхимия ORM возвращает один столбец, как избежать общей постобработки

[(result,), (result_2,)] # etc... 

с набором как это я считаю, что я должен делать это часто:

results = [r[0] for r in results] # So that I just have a list of result values 

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

Есть ли способ избежать этого дополнительного шага?

Связанных в стороне: Такое поведение ОРМА кажется неудобным в этом случае, но другой случай, когда мой результирующий набор был, [(идентификатор, значение)] он заканчивает так:

[(result_1_id, result_1_val), (result_2_id, result_2_val)] 

Я тогда может только сделать:

results = dict(results) # so I have a map of id to value 

Это преимущество имеет смысл сделать полезный шаг после возвращения результатов.

Действительно ли это проблема, или я просто являюсь nitpick, и после обработки после получения набора результатов имеет смысл для обоих случаев? Я уверен, что мы можем думать о некоторых других обычных операциях пост-обработки, чтобы сделать набор результатов более полезным в коде приложения. Есть ли высокая производительность и удобные решения по всем направлениям или неуправляемость почтовой обработки и просто требуется для разных применений приложений?

Когда мое приложение действительно может воспользоваться объектами, возвращаемыми ORM SQL Alchemy, это кажется чрезвычайно полезным, но в тех случаях, когда я не могу или не хочу, не так много. Это просто общая проблема ORM в целом? Мне лучше не использовать слой ORM в таких случаях?

Я полагаю, я должен показать пример реальных ORM запросов о которых я говорю:

session.query(OrmObj.column_name).all() 

или

session.query(OrmObj.id_column_name, OrmObj.value_column_name).all() 

Конечно, в реальном запросе там бы нормально некоторое фильтров и т. д.

ответ

19

Почтовый индекс Python в сочетании с оператором расширения inline является довольно удобным решением:

>>> results = [('result',), ('result_2',), ('result_3',)] 
>>> zip(*results) 
[('result', 'result_2', 'result_3')] 

Тогда вам нужно только указать [0] индекс за один раз. За столь короткий список ваше понимание быстрее:

>>> timeit('result = zip(*[("result",), ("result_2",), ("result_3",)])', number=10000) 
0.010490894317626953 
>>> timeit('result = [ result[0] for result in [("result",), ("result_2",), ("result_3",)] ]', number=10000) 
0.0028390884399414062 

Однако для более длинные списки застежка-молния должна быть быстрее:

>>> timeit('result = zip(*[(1,)]*100)', number=10000) 
0.049577951431274414 
>>> timeit('result = [ result[0] for result in [(1,)]*100 ]', number=10000) 
0.11178708076477051 

Так это до вас, чтобы определить, что лучше для вашей ситуации.

10

Одним из способов уменьшения помех в источнике является итерацию, как это:

results = [r for (r,) in results] 

Хотя это решение один символ больше, чем при использовании [] оператора, я думаю, что это легче на глазах.

Чтобы еще меньше загромождать, удалите скобки. Это делает его более трудным при чтении кода, чтобы заметить, что вы на самом деле обработки кортежей, хотя:

results = [r for r, in results] 
8

Я боролся с этим тоже, пока я не понял, что это так же, как любой другой запрос:

for result in results: 
    print result.column_name 
+0

Да, я согласен, NamedTuples не сразу очевидны. Моя самая обычная почтовая обработка по-прежнему создает какой-то словарь. Большая часть моей обработки сообщений была устранена с помощью лучшей архитектуры базы данных и использования SQLAlchemy, поэтому у меня есть значения, которые мне нужно привязать к объектам ORM, или доступны с помощью методов. –

0

Мое решение выглядит следующим образом:)

def column(self): 
    for column, *_ in Model.query.with_entities(Model.column).all(): 
     yield column 

ПРИМЕЧАНИЕ: только py3.

1

я нашел следующее более читаемым, также включает в ответ на Dict (в Python 2.7):

d = {id_: name for id_, name in session.query(Customer.id, Customer.name).all()} 
l = [r.id for r in session.query(Customer).all()] 

Для одного значения, заимствование из другого ответа:

l = [name for (name,) in session.query(Customer.name).all()] 

Сравните со встроенным решением zip, адаптированное к списку:

l = list(zip(*session.query(Customer.id).all())[0]) 

, который в моём времени обеспечивает только улучшение скорости на 4%.

0

Ничего себе, ребята, зачем напрягать? Есть метод более крутой путь, быстрее и изящнее)

>>> results = [('result',), ('result_2',), ('result_3',)] 
>>> sum(results, tuple()) 
('result', 'result_2', 'result_3') 

Скорость:

>>> timeit('result = zip(*[("result",), ("result_2",), ("result_3",)])', number=10000) 
0.004222994000883773 
>>> timeit('result = sum([("result",), ("result_2",), ("result_3",)],())', number=10000) 
0.0038205889868550003 

Но если больше элементов в списке - использовать только почтовый. Zip больше скорости.

Смежные вопросы