Рассмотрим следующий код python2
In [5]: points = [ (1,2), (2,3)]
In [6]: min(points, key=lambda (x, y): (x*x + y*y))
Out[6]: (1, 2)
Это не поддерживается в python3, и мне нужно сделать следующее:
>>> min(points, key=lambda p: p[0]*p[0] + p[1]*p[1])
(1, 2)
Это очень некрасиво. Если бы лямбда была функцией, я мог бы сделать
def some_name_to_think_of(p):
x, y = p
return x*x + y*y
Удаление этой функции в python3 заставляет код либо действовать некрасиво (с магическими индексами), либо создавать ненужные функции (самая неприятная часть - придумать хорошие имена для этих ненужных функций)
Я думаю, что эту функцию следует добавить хотя бы только к лямбдам. Есть ли хорошая альтернатива?
Обновление: я использую следующий помощник, расширяющий идею в ответе
def star(f):
return lambda args: f(*args)
min(points, key=star(lambda x,y: (x*x + y*y))
Update2: более чистая версия дляstar
import functools
def star(f):
@functools.wraps(f):
def f_inner(args):
return f(*args)
return f_inner
python
python-3.x
балки
источник
источник
lambda
будет полностью удален из языка, чем отменить изменения, которые усложнили его использование, но вы можете попробовать опубликовать на python-ideas, если вы хотите выразить желание увидеть добавленную функцию.lambda
в том же духе, что и онmap
,reduce
иfilter
.lambda
был намечен для удаления в py3k, так как это в основном вред для языка. Но никто не мог договориться о подходящей альтернативе для определения анонимных функций, поэтому в конце концов Гвидо вскинул руки в поражении, и все.map
иfilter
лучше всего заменены пониманием, мне нравитсяreduce
)Ответы:
Нет, другого выхода нет. Вы все это покрыли. Можно было бы поднять этот вопрос в списке рассылки идей Python , но будьте готовы много спорить там, чтобы получить некоторую поддержку.
На самом деле, просто чтобы не сказать «выхода нет», третий способ может заключаться в реализации еще одного уровня лямбда-вызова, просто чтобы развернуть параметры - но это было бы одновременно более неэффективно и труднее для чтения, чем два ваших предложения:
min(points, key=lambda p: (lambda x,y: (x*x + y*y))(*p))
обновить Python 3.8
На данный момент доступен Python 3.8 alpha1 и реализованы выражения присваивания PEP 572-.
Итак, если кто-то использует уловку для выполнения нескольких выражений внутри лямбда-выражения - я обычно делаю это, создавая кортеж и просто возвращая последний его компонент, это можно сделать:
>>> a = lambda p:(x:=p[0], y:=p[1], x ** 2 + y ** 2)[-1] >>> a((3,4)) 25
Следует иметь в виду, что такой код редко бывает более удобочитаемым или практичным, чем полнофункциональный. Тем не менее, есть возможные применения - если есть различные однострочные, которые будут работать с этим
point
, может быть полезно иметь namedtuple и использовать выражение присваивания для эффективного «приведения» входящей последовательности к namedtuple:>>> from collections import namedtuple >>> point = namedtuple("point", "x y") >>> b = lambda s: (p:=point(*s), p.x ** 2 + p.y ** 2)[-1]
источник
def
, указанную в вопросе под nmesome_name_to_think-of
.key = lambda p: (x:=p[0], y:=p[1], x ** 2 + y ** 2)[-1]
Согласно http://www.python.org/dev/peps/pep-3113/ распаковка кортежей исчезла и
2to3
переведет их так:Что очень похоже на вашу реализацию.
источник
Я не знаю хороших общих альтернатив распаковке аргументов Python 2. Вот пара предложений, которые могут быть полезны в некоторых случаях:
если вы не можете придумать имя; используйте имя параметра ключевого слова:
def key(p): # more specific name would be better x, y = p return x**2 + y**3 result = min(points, key=key)
вы можете увидеть,
namedtuple
делает ли ваш код более читаемым, если список используется в нескольких местах:from collections import namedtuple from itertools import starmap points = [ (1,2), (2,3)] Point = namedtuple('Point', 'x y') points = list(starmap(Point, points)) result = min(points, key=lambda p: p.x**2 + p.y**3)
источник
lambda (x, y):
иlambda x, y:
не очевидна на первый взгляд.Хотя аргументы деструктуризации были удалены в Python3, они не были удалены из понимания. Можно злоупотребить им для получения аналогичного поведения в Python 3. По сути, мы пользуемся преимуществом того факта, что совместные подпрограммы позволяют нам выворачивать функции наизнанку, а yield не является оператором и, следовательно, разрешен в лямбдах.
Например:
points = [(1,2), (2,3)] print(min(points, key=lambda y: next(x*x + y*y for x,y in (lambda a: (yield a))(y))))
По сравнению с принятым ответом об использовании оболочки это решение способно полностью разрушить аргументы, в то время как оболочка разрушает только первый уровень. То есть,
values = [(('A',1),'a'), (('B',0),'b')] print(min(values, key=lambda y: next(b for (a,b),c in (lambda x: (yield x))(y))))
В сравнении с
values = [(('A',1),'a'), (('B',0),'b')] print(min(points, key=lambda p: (lambda a,b: (lambda x,y: (y))(*a))(*p)))
В качестве альтернативы можно также сделать
values = [(('A',1),'a'), (('B',0),'b')] print(min(points, key=lambda y: next(b for (a,b),c in [y])))
Или чуть лучше
print(min(values, key=lambda y: next(b for ((a,b),c) in (y,))))
Это всего лишь предположение, что это можно сделать, и не следует воспринимать это как рекомендацию.
источник
Я думаю, что лучше синтаксис
x * x + y * y let x, y = point
,let
ключевое слово следует выбирать более тщательно.Двойная лямбда - ближайшая версия.
lambda point: (lambda x, y: x * x + y * y)(*point)
Вспомогательная функция высокого порядка будет полезна, если мы дадим ей собственное имя.
def destruct_tuple(f): return lambda args: f(*args) destruct_tuple(lambda x, y: x * x + y * y)
источник
Основываясь на предложении Cuadue и вашем комментарии о распаковке, который все еще присутствует в понимания, вы можете использовать, используя
numpy.argmin
:result = points[numpy.argmin(x*x + y*y for x, y in points)]
источник
Другой вариант - записать его в генератор, создав кортеж, в котором ключ является первым элементом. Кортежи сравниваются от начала до конца, поэтому возвращается кортеж с наименьшим первым элементом. Затем вы можете проиндексировать результат, чтобы получить значение.
min((x * x + y * y, (x, y)) for x, y in points)[1]
источник
Подумайте, нужно ли вам распаковывать кортеж в первую очередь:
min(points, key=lambda p: sum(x**2 for x in p))
или нужно ли указывать явные имена при распаковке:
min(points, key=lambda p: abs(complex(*p))
источник