web-dev-qa-db-fra.com

Comment utiliser wait dans un python lambda

J'essaie de faire quelque chose comme ça:

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

Mais je reçois cette erreur:

SyntaxError: 'await' outside async function

Ce qui est logique car le lambda n'est pas asynchrone.

J'ai essayé d'utiliser async lambda x: ... mais cela jette un SyntaxError: invalid syntax.

Pep 492 déclare:

La syntaxe des fonctions lambda asynchrones pourrait être fournie, mais cette construction est en dehors de la portée de ce PEP.

Mais je n'ai pas pu savoir si cette syntaxe était implémentée dans CPython.

Existe-t-il un moyen de déclarer un lambda asynchrone ou d'utiliser une fonction asynchrone pour trier une liste?

19
iCart

Tu ne peux pas. Il n'y a pas de async lambda, Et même s'il y en avait, vous ne pouvez pas le passer comme fonction clé à list.sort(), car une fonction clé sera appelée comme fonction synchrone et non attendue. Une solution simple consiste à annoter vous-même votre liste:

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

Notez que les expressions await dans les compréhensions de liste ne sont prises en charge que dans Python 3.6+. Si vous utilisez 3.5, vous pouvez effectuer les opérations suivantes:

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

La réponse de Sven Marnach a un cas Edge.

Si vous essayez de trier une liste qui contient 2 éléments qui produisent la même clé de recherche mais qui sont différents et ne sont pas directement triables, elle se bloque.

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

Va donner:

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

Heureusement, j'avais une solution simple - mes données avaient une clé unique qui était triable, donc je pouvais mettre cela comme deuxième clé:

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

Je suppose que si vos données n'ont pas de valeur naturellement unique, vous pouvez en insérer une avant d'essayer de trier? Un uuide peut-être?

MODIFIER : Comme suggéré dans le commentaire (merci!), vous pouvez également utiliser 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