web-dev-qa-db-ja.com

pythonラムダでawaitを使用する方法

私はこのようなことをやろうとしています:

mylist.sort(key=lambda x: await somefunction(x))

しかし、私はこのエラーを受け取ります:

SyntaxError: 'await' outside async function

ラムダは非同期ではないので、これは理にかなっています。

async lambda x: ...を使用しようとしましたが、SyntaxError: invalid syntaxがスローされます。

Pep 492 の状態:

非同期ラムダ関数の構文を指定できますが、この構成はこのPEPの範囲外です。

しかし、その構文がCPythonで実装されているかどうかはわかりませんでした。

非同期ラムダを宣言する方法、または非同期関数を使用してリストをソートする方法はありますか?

19
iCart

できません。 _async lambda_はなく、キー関数は同期関数として呼び出され、待機されないため、キー関数としてlist.sort()に渡すことはできません。簡単な回避策は、自分でリストに注釈を付けることです。

_mylist_annotated = [(await some_function(x), x) for x in mylist]
mylist_annotated.sort()
mylist = [x for key, x in mylist_annotated]
_

リスト内包表記のawait式は、Python 3.6+でのみサポートされています。3.5を使用している場合は、次のことができます。

_mylist_annotated = []
for x in mylist:
    mylist_annotated.append((await some_function(x), x)) 
mylist_annotated.sort()
mylist = [x for key, x in mylist_annotated]
_
22
Sven Marnach

Sven Marnachからの回答にはEdgeケースがあります。

同じ検索キーを生成するが、異なるため直接ソートできない2つのアイテムがあるリストをソートしようとすると、クラッシュします。

mylist = [{'score':50,'name':'bob'},{'score':50,'name':'linda'}]

mylist_annotated = [(x['score'], x) for x in mylist]
mylist_annotated.sort()
print( [x for key, x in mylist_annotated] )

あげる:

TypeError: '<' not supported between instances of 'dict' and 'dict'

幸い、私には簡単な解決策がありました。私のデータには並べ替え可能な一意のキーがあり、それを2番目のキーとして使用できます。

mylist = [{'score':50,'name':'bob','unique_id':1},{'score':50,'name':'linda','unique_id':2}]

mylist_annotated = [(x['score'], x['unique_id'], x) for x in mylist]
mylist_annotated.sort()
print( [x for key, unique, x in mylist_annotated] )

データに自然に一意の値がない場合は、並べ替える前に値を挿入できますか?おそらくuuid?

[〜#〜] edit [〜#〜]:コメントで提案されているように(ありがとう!)、operator.itemgetterを使用することもできます。

import operator

mylist = [{'score':50,'name':'bob'},{'score':50,'name':'linda'}]

mylist_annotated = [(x['score'], x) for x in mylist]
mylist_annotated.sort(key=operator.itemgetter(0))
print( [x for key, x in mylist_annotated] )
1
James