2012-02-28 4 views
49

を避けるために、私は見つけますこのように私は頻繁にこれをしなければならないことを見つける:私の結果セットが通常は小さいですが、彼らがいなかったならば、これは大きなオーバーヘッドを追加する可能性があるためSQL錬金術ORMは、どのように私はSQL錬金術のORMを使用しています一般的な後処理

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

これが「悪い」ということではありません。もっとも大きなことは、ソースがクラッタしていると感じることです。このステップを逃すことは、私が実行している非常に一般的なエラーです。

この余分なステップを避ける方法はありますか?

Aはさておき関連:私はその後、

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

:ORMのこの動作は、この場合には不便が、私の結果セットが、それはこのように終わる[(ID、値)]であった別のケースと思われますちょうど行うことができます。

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

この1が結果を返した後に有用ステップとしての意味を作るという利点を有しています。

これは本当に問題なのでしょうか、私はちょうどニットピックで、結果セットを取得した後の後処理はどちらの場合にも意味がありますか?結果セットをアプリケーションコードでより使いやすくするために、他の一般的な後処理操作について考えることができます。高性能で便利なソリューションが全面的に提供されているのか、やむを得ない後処理であり、アプリケーションの用途を変えるだけで必要なのでしょうか?

私のアプリケーションがSQL AlchemyのORMによって返されるオブジェクトを実際に利用できるようになると、非常に役立つように見えますが、できない場合やそうでない場合はそうはなりません。これは一般的なORMの一般的な問題ですか?このような場合にORMレイヤーを使用しないほうがいいですか?

私は私が話している実際のORMクエリの一例を示すべきであるとします

もちろん
session.query(OrmObj.column_name).all() 

または

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

、実際のクエリでは、通常、いくつかのがあると思いますフィルタなど

答えて

19

*インライン展開演算子と組み合わせたPythonのジップは、これに非常に便利なソリューションです:

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

このソリューションは、1つの文字長い[]演算子を使用するよりもですが、私はそれが目に簡単だと思います。

さらに混乱させるには、括弧を削除します。

for result in results: 
    print result.column_name 
8

は私もこれで苦労:これは、コードを読むとき、あなたが実際にかかわらず、タプルを処理していることに注意することが難しく、それを作ります私のソリューションはこのように見えます;)

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

注:py3のみ。

+0

はい、私は同意します、NamedTuplesはすぐに明らかではありません。私の最も一般的な後処理は、まだいくつかの種類の辞書を作成する必要があります。私の後処理の大部分は、より良いデータベースアーキテクチャとSQLAlchemyの使用法によって排除されているので、ORMオブジェクトに付随しているか、メソッドを通じて利用可能な値を持っています。 –

0

:私はそれだけで、他のクエリのようなものだ実現するまで

results = [r for r, in results] 
1

私も(Pythonの2.7で)dictのための答えが含まれ、以下のより読みやすいが見つかりました:単一の値については

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

l = list(zip(*session.query(Customer.id).all())[0]) 
内蔵の zipソリューションと比較してください。

私の時間では約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 

しかし、リストでより多くの要素があれば - のみジップ使用しています。より速いスピード。

関連する問題