У меня есть список объектов, и я хочу удалить все пустые объекты, кроме одного, с использованием filter
и lambda
выражения.
Например, если ввод:
[Object(name=""), Object(name="fake_name"), Object(name="")]
... тогда вывод должен быть:
[Object(name=""), Object(name="fake_name")]
Есть ли способ добавить присвоение lambda
выражению? Например:
flag = True
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(
(lambda o: [flag or bool(o.name), flag = flag and bool(o.name)][0]),
input
)
Ответы:
Оператор выражения присваивания,
:=
добавленный в Python 3.8, поддерживает присваивание внутри лямбда-выражений. Этот оператор может появляться только в скобках(...)
, скобках[...]
или{...}
выражениях в скобках по синтаксическим причинам. Например, мы сможем написать следующее:В Python 2 было возможно выполнять локальные назначения как побочный эффект понимания списков.
Однако в вашем примере невозможно использовать ни один из них, потому что ваша переменная
flag
находится во внешней области видимости, а не вlambda
области видимости. Это не имеет отношения к этомуlambda
, это общее поведение в Python 2. Python 3 позволяет обойти это с помощьюnonlocal
ключевого слова внутриdef
s, ноnonlocal
не может использоваться внутриlambda
s.Есть обходной путь (см. Ниже), но пока мы обсуждаем эту тему ...
В некоторых случаях вы можете использовать это, чтобы делать все внутри
lambda
:Пожалуйста, не надо.
... вернемся к исходному примеру: хотя вы не можете выполнять назначения для
flag
переменной во внешней области видимости, вы можете использовать функции для изменения ранее присвоенного значения.Например, это
flag
может быть объект, который.value
мы установили с помощьюsetattr
:Если бы мы хотели соответствовать указанной выше теме, мы могли бы использовать понимание списка вместо
setattr
:Но на самом деле в серьезном коде вы всегда должны использовать обычное определение функции вместо a,
lambda
если вы собираетесь выполнять внешнее присвоение.источник
.setattr()
и похожие (например, словари тоже должны), чтобы в любом случае взламывать побочные эффекты в функциональный код, был показан классный код от @JeremyBanks :)assignment operator
!Вы не можете поддерживать состояние в выражении
filter
/lambda
(если не злоупотребляете глобальным пространством имен). Однако вы можете добиться чего-то подобного, используя накопленный результат, передаваемый вreduce()
выражении:Конечно, вы можете немного изменить это условие. В этом случае он отфильтровывает дубликаты, но вы также можете использовать
a.count("")
, например, только для ограничения пустых строк.Излишне говорить, что вы можете это сделать, но на самом деле не должны. :)
Наконец, вы можете делать все на чистом Python
lambda
: http://vanderwijk.info/blog/pure-lambda-calculus-python/источник
Нет необходимости использовать лямбда, когда вы можете удалить все нулевые значения и вернуть один, если размер ввода изменится:
источник
output = [x for x in input if x.name]
.Обычное присвоение (
=
) невозможно внутриlambda
выражения, хотя можно выполнять различные трюки сsetattr
и друзьями.Однако решить вашу проблему на самом деле довольно просто:
что даст вам
Как видите, он сохраняет первый пустой экземпляр вместо последнего. Если вместо этого вам нужен последний, переверните
filter
список, входящий в , и переверните список, выходящий изfilter
:что даст вам
Одна вещь, о которой нужно знать: для того, чтобы это работало с произвольными объектами, эти объекты должны быть правильно реализованы
__eq__
и,__hash__
как описано здесь .источник
ОБНОВЛЕНИЕ :
или используя
filter
иlambda
:Предыдущий ответ
Хорошо, вы застряли на использовании фильтра и лямбды?
Похоже, это было бы лучше подавать с пониманием словаря,
Я думаю, что причина того, что Python не разрешает присваивание в лямбде, аналогична тому, почему он не допускает присваивания в понимании, и это как-то связано с тем фактом, что эти вещи оцениваются на
C
стороне и, таким образом, могут дать нам увеличение скорости. По крайней мере, таково мое впечатление после прочтения одного из эссе Гвидо. .Я предполагаю, что это также противоречит философии наличия одного правильного способа сделать что-либо в Python.
источник
TL; DR: при использовании функциональных идиом лучше писать функциональный код
Как отмечали многие люди, в Python присвоение лямбда-выражений не допускается. В общем, при использовании функциональных идиом лучше думать функционально, что означает отсутствие побочных эффектов и назначений везде, где это возможно.
Вот функциональное решение, в котором используется лямбда. Я назначил лямбду
fn
для ясности (и потому, что она немного затянута).Вы также можете решить эту проблему с помощью итераторов, а не списков, немного изменив ситуацию. У вас также есть другой импорт.
Вы всегда можете реорганизовать код, чтобы уменьшить длину операторов.
источник
Если вместо этого
flag = True
мы можем выполнить импорт, то я думаю, что это соответствует критериям:Или, может быть, фильтр лучше написать так:
Или просто для простого логического значения без импорта:
источник
Питонический способ отслеживать состояние во время итерации - с помощью генераторов. Способ itertools довольно сложен для понимания IMHO, и пытаться взломать лямбды для этого просто глупо. Я бы попробовал:
В целом, удобочитаемость всегда важнее компактности.
источник
Нет, вы не можете поместить присвоение внутри лямбды из-за его собственного определения. Если вы работаете с использованием функционального программирования, вы должны предполагать, что ваши значения неизменяемы.
Одним из решений может быть следующий код:
источник
Если вам нужна лямбда для запоминания состояния между вызовами, я бы порекомендовал либо функцию, объявленную в локальном пространстве имен, либо класс с перегруженным
__call__
. Теперь, когда все мои предостережения против того, что вы пытаетесь сделать, исчезли, мы можем перейти к фактическому ответу на ваш вопрос.Если вам действительно нужно, чтобы ваша лямбда имела некоторую память между вызовами, вы можете определить ее следующим образом:
Тогда вам просто нужно перейти
f
наfilter()
. Если вам действительно нужно, вы можете вернуть значениеflag
с помощью следующего:Кроме того, вы можете изменить глобальное пространство имен, изменив результат
globals()
. К сожалению, вы не можете изменить локальное пространство имен таким же образом, как изменение результатаlocals()
не влияет на локальное пространство имен.источник
(let ((var 42)) (lambda () (setf var 43)))
.Вы можете использовать функцию привязки, чтобы использовать псевдо-многопозиционную лямбду. Затем вы можете использовать класс-оболочку для флага, чтобы разрешить назначение.
источник
Это своего рода грязный обходной путь, но назначение в лямбдах в любом случае незаконно, поэтому на самом деле это не имеет значения. Вы можете использовать встроенную
exec()
функцию для выполнения присваивания из лямбда-выражения, например, в этом примере:источник
Во-первых, вам не нужно использовать местное задание для вашей работы, просто проверьте ответ выше
во-вторых, просто использовать locals () и globals (), чтобы получить таблицу переменных, а затем изменить значение
проверьте этот пример кода:
если вам нужно изменить добавление глобальной переменной в среду, попробуйте заменить locals () на globals ()
Составление списка в python - это круто, но большая часть трехкомпонентного проекта этого не принимает (например, flask: [)
надеюсь, это может помочь
источник
locals()
, в документации прямо сказано, что его изменение на самом деле не меняет локальную область (или, по крайней мере, не всегда).globals()
с другой стороны работает как ожидалось.globals()
. pastebin.com/5Bjz1mR4 (проверено как в 2.6, так и в 3.2) доказывает это.