Considérez le code python2 suivant
In [5]: points = [ (1,2), (2,3)]
In [6]: min(points, key=lambda (x, y): (x*x + y*y))
Out[6]: (1, 2)
Cela n'est pas pris en charge dans python3 et je dois faire ce qui suit:
>>> min(points, key=lambda p: p[0]*p[0] + p[1]*p[1])
(1, 2)
C'est très moche. Si le lambda était une fonction, je pourrais faire
def some_name_to_think_of(p):
x, y = p
return x*x + y*y
La suppression de cette fonctionnalité dans python3 oblige le code à faire la moche (avec des index magiques) ou à créer des fonctions inutiles (la partie la plus ennuyeuse est de penser à de bons noms pour ces fonctions inutiles)
Je pense que la fonctionnalité devrait être ajoutée au moins aux lambdas seuls. Y a-t-il une bonne alternative?
Mise à jour: j'utilise l'aide suivante pour étendre l'idée dans la réponse
def star(f):
return lambda args: f(*args)
min(points, key=star(lambda x,y: (x*x + y*y))
Update2: une version plus propre pourstar
import functools
def star(f):
@functools.wraps(f):
def f_inner(args):
return f(*args)
return f_inner
python
python-3.x
balki
la source
la source
lambda
d'être complètement supprimé du langage que d'annuler les modifications qui le rendaient plus difficile à utiliser, mais vous pouvez essayer de publier sur python-ideas si vous souhaitez exprimer le désir de voir la fonctionnalité ajoutée.lambda
dans le même esprit qu'il s'opposemap
,reduce
etfilter
.lambda
devait être supprimé dans py3k car il s'agit essentiellement d'un fléau pour la langue. Mais personne ne pouvait s'entendre sur une alternative appropriée pour définir les fonctions anonymes, alors Guido a finalement jeté les bras en signe de défaite et c'était tout.map
etfilter
sont mieux remplacés par des compréhensions, j'aime bienreduce
)Réponses:
Non, il n'y a pas d'autre moyen. Vous avez tout couvert. La voie à suivre serait de soulever cette question sur le liste de diffusion des idées Python , mais soyez prêt à discuter beaucoup là-bas pour gagner du terrain.
En fait, pour ne pas dire "il n'y a pas d'issue", une troisième façon pourrait être d'implémenter un niveau supplémentaire d'appel lambda juste pour déplier les paramètres - mais ce serait à la fois plus inefficace et plus difficile à lire que vos deux suggestions:
mettre à jour Python 3.8
A partir de maintenant, Python 3.8 alpha1 est disponible et les expressions d'affectation PEP 572 sont implémentées.
Donc, si on utilise une astuce pour exécuter plusieurs expressions à l'intérieur d'un lambda - je le fais généralement en créant un tuple et en renvoyant simplement le dernier composant, il est possible de faire:
Il faut garder à l'esprit que ce type de code sera rarement plus lisible ou plus pratique que d'avoir une fonction complète. Pourtant, il y a des utilisations possibles - s'il y a plusieurs one-liners qui opéreraient là
point
-dessus, cela pourrait valoir la peine d'avoir un namedtuple et d'utiliser l'expression d'affectation pour effectivement "transtyper" la séquence entrante vers le namedtuple:la source
def
qui est mentionné dans la question sous le nmesome_name_to_think-of
.key = lambda p: (x:=p[0], y:=p[1], x ** 2 + y ** 2)[-1]
Selon http://www.python.org/dev/peps/pep-3113/, le déballage des tuple a disparu et
2to3
les traduira comme suit:Ce qui est assez similaire à votre implémentation.
la source
Je ne connais pas de bonnes alternatives générales au comportement de décompression des arguments de Python 2. Voici quelques suggestions qui pourraient être utiles dans certains cas:
si vous ne pouvez pas penser à un nom; utilisez le nom du paramètre de mot-clé:
vous pouvez voir si a
namedtuple
rend votre code plus lisible si la liste est utilisée à plusieurs endroits:la source
lambda (x, y):
etlambda x, y:
n'est pas évidente à première vue.Bien que les arguments de déstructuration aient été supprimés dans Python3, ils n'ont pas été supprimés des compréhensions. Il est possible d'en abuser pour obtenir un comportement similaire en Python 3. En substance, nous profitons du fait que les co-routines nous permettent de retourner les fonctions à l'envers, et yield n'est pas une instruction, et est donc autorisé dans lambdas.
Par exemple:
En comparaison avec la réponse acceptée d'utiliser un wrapper, cette solution est capable de déstructurer complètement les arguments tandis que le wrapper ne déstructure que le premier niveau. C'est,
En comparaison à
Alternativement, on peut aussi faire
Ou légèrement mieux
Il s'agit simplement de suggérer que cela peut être fait et ne doit pas être considéré comme une recommandation.
la source
Sur la base de la suggestion de Cuadue et de votre commentaire sur le déballage toujours présent dans les compréhensions, vous pouvez utiliser, en utilisant
numpy.argmin
:la source
Une autre option est de l'écrire dans un générateur produisant un tuple où la clé est le premier élément. Les tuples sont comparés du début à la fin afin que le tuple avec le premier élément le plus petit soit renvoyé. Vous pouvez ensuite indexer le résultat pour obtenir la valeur.
la source
Déterminez si vous devez décompresser le tuple en premier lieu:
ou si vous devez fournir des noms explicites lors de la décompression:
la source
Je pense que la meilleure syntaxe est
x * x + y * y let x, y = point
, lelet
mot - clé devrait être choisi plus soigneusement.Le double lambda est la version la plus proche.
lambda point: (lambda x, y: x * x + y * y)(*point)
Un assistant de fonction d'ordre élevé serait utile au cas où nous lui donnerions un nom correct.
la source