Considere el siguiente código de python2
In [5]: points = [ (1,2), (2,3)]
In [6]: min(points, key=lambda (x, y): (x*x + y*y))
Out[6]: (1, 2)
Esto no es compatible con python3 y tengo que hacer lo siguiente:
>>> min(points, key=lambda p: p[0]*p[0] + p[1]*p[1])
(1, 2)
Esto es muy feo. Si la lambda fuera una función, podría hacer
def some_name_to_think_of(p):
x, y = p
return x*x + y*y
La eliminación de esta función en python3 obliga al código a hacer lo feo (con índices mágicos) o crear funciones innecesarias (la parte más molesta es pensar en buenos nombres para estas funciones innecesarias)
Creo que la función debería volver a agregarse al menos solo a las lambdas. ¿Existe una buena alternativa?
Actualización: estoy usando el siguiente ayudante extendiendo la idea en la respuesta
def star(f):
return lambda args: f(*args)
min(points, key=star(lambda x,y: (x*x + y*y))
Update2: una versión más limpia parastar
import functools
def star(f):
@functools.wraps(f):
def f_inner(args):
return f(*args)
return f_inner
python
python-3.x
balki
fuente
fuente
lambda
que se elimine del lenguaje por completo que revertir los cambios que lo hicieron más difícil de usar, pero podría intentar publicar en Python-ideas si desea expresar su deseo de que se vuelva a agregar la función.lambda
con el mismo espíritu que se oponemap
,reduce
yfilter
.lambda
estaba programado para su eliminación en py3k, ya que básicamente es una plaga para el lenguaje. Pero nadie pudo ponerse de acuerdo sobre una alternativa adecuada para definir funciones anónimas, por lo que eventualmente Guido levantó los brazos en señal de derrota y eso fue todo.map
yfilter
se reemplazan mejor por comprensiones, me gustareduce
)Respuestas:
No, no hay otra manera. Lo cubriste todo. El camino a seguir sería plantear este problema en la lista de correo de ideas de Python , pero prepárese para discutir mucho allí para ganar algo de tracción.
En realidad, para no decir "no hay salida", una tercera forma podría ser implementar un nivel más de llamada lambda solo para desplegar los parámetros, pero eso sería a la vez más ineficiente y más difícil de leer que sus dos sugerencias:
actualizar Python 3.8
A partir de ahora, Python 3.8 alpha1 está disponible y se implementan las expresiones de asignación PEP 572-.
Entonces, si uno usa un truco para ejecutar múltiples expresiones dentro de una lambda, generalmente lo hago creando una tupla y simplemente devolviendo el último componente de la misma, es posible hacer:
Se debe tener en cuenta que este tipo de código rara vez será más legible o práctico que tener una función completa. Aún así, hay usos posibles: si hay varias
point
frases ingeniosas que operarían en esto , podría valer la pena tener una tupla con nombre y usar la expresión de asignación para "lanzar" efectivamente la secuencia entrante a la tupla con nombre:fuente
def
que se menciona en la pregunta debajo del nombresome_name_to_think-of
.key = lambda p: (x:=p[0], y:=p[1], x ** 2 + y ** 2)[-1]
Según http://www.python.org/dev/peps/pep-3113/, el desempaquetado de tuplas se ha ido y
2to3
los traducirá así:Lo cual es bastante similar a su implementación.
fuente
No conozco ninguna buena alternativa general al comportamiento de desempaquetado de argumentos de Python 2. Aquí hay un par de sugerencias que pueden resultar útiles en algunos casos:
si no puede pensar en un nombre; use el nombre del parámetro de palabra clave:
podría ver si
namedtuple
hace que su código sea más legible si la lista se usa en varios lugares:fuente
lambda (x, y):
ylambda x, y:
no es obvia a primera vista.Si bien los argumentos de desestructuración se eliminaron en Python3, no se eliminaron de las comprensiones. Es posible abusar de él para obtener un comportamiento similar en Python 3. En esencia, aprovechamos el hecho de que las co-rutinas nos permiten darle la vuelta a las funciones, y el rendimiento no es una declaración y, por lo tanto, está permitido dentro de lambdas.
Por ejemplo:
En comparación con la respuesta aceptada de usar un contenedor, esta solución es capaz de desestructurar completamente los argumentos mientras que el contenedor solo desestructura el primer nivel. Es decir,
En comparación con
Alternativamente, también se puede hacer
O un poco mejor
Esto es solo para sugerir que se puede hacer y no debe tomarse como una recomendación.
fuente
Según la sugerencia de Cuadue y su comentario sobre cómo desempacar aún está presente en las comprensiones, puede usar, usando
numpy.argmin
:fuente
Otra opción es escribirlo en un generador que produzca una tupla donde la clave es el primer elemento. Las tuplas se comparan desde el principio hasta el final, por lo que se devuelve la tupla con el primer elemento más pequeño. Luego puede indexar en el resultado para obtener el valor.
fuente
Considere si necesita descomprimir la tupla en primer lugar:
o si necesita proporcionar nombres explícitos al desembalar:
fuente
Creo que la mejor es la sintaxis
x * x + y * y let x, y = point
,let
la palabra clave debe ser más cuidadosamente elegido.La doble lambda es la versión más cercana.
lambda point: (lambda x, y: x * x + y * y)(*point)
El ayudante de función de orden superior sería útil en caso de que le demos un nombre adecuado.
fuente