Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assignment inside lambda expression in Python

I have a list of objects and I want to remove all objects that are empty except for one, using filter and a lambda expression.

For example if the input is:

[Object(name=""), Object(name="fake_name"), Object(name="")] 

...then the output should be:

[Object(name=""), Object(name="fake_name")] 

Is there a way to add an assignment to a lambda expression? For example:

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 ) 
like image 401
Cat Avatar asked Jun 08 '11 16:06

Cat


People also ask

Can a lambda function be assigned to a variable?

Creating a Lambda Function The lambda operator cannot have any statements and it returns a function object that we can assign to any variable.

Can we write nested lambda function in Python?

Python allows lambda nesting, i.e., you can create another lambda function inside a pre-existing lambda function. For nesting lambdas, you will need to define two lambda functions – an outer and an inner lambda function. When the outer lambda is called, the inner lambda creates a function.

Do not assign a lambda expression use a Def?

Always use a def statement instead of an assignment statement that binds a lambda expression directly to a name. Assigning lambdas to names basically just duplicates the functionality of def - and in general, it's best to do something a single way to avoid confusion and increase clarity.

How to assign an expression inside of a lambda expression?

The assignment expression operator :=added in Python 3.8supports assignment inside of lambda expressions. This operator can only appear within a parenthesized (...), bracketed [...], or braced {...}expression for syntactic reasons. For example, we will be able to write the following:

Why are lambda functions not used in Python?

Python does not encourage using immediately invoked lambda expressions. It simply results from a lambda expression being callable, unlike the body of a normal function. Lambda functions are frequently used with higher-order functions, which take one or more functions as arguments or return one or more functions.

How many arguments can a lambda function take?

A lambda function is a small anonymous function. A lambda function can take any number of arguments, but can only have one expression. Add 10 to argument a, and return the result:

What are assignment expressions in Python?

In this tutorial, you used assignment expressions to make compact sections of Python code that assign values to variables inside of if statements, while loops, and list comprehensions. For more information on other assignment expressions, you can view PEP 572 —the document that initially proposed adding assignment expressions to Python.


1 Answers

The assignment expression operator := added in Python 3.8 supports assignment inside of lambda expressions. This operator can only appear within a parenthesized (...), bracketed [...], or braced {...} expression for syntactic reasons. For example, we will be able to write the following:

import sys say_hello = lambda: (     message := "Hello world",     sys.stdout.write(message + "\n") )[-1] say_hello() 

In Python 2, it was possible to perform local assignments as a side effect of list comprehensions.

import sys say_hello = lambda: (     [None for message in ["Hello world"]],     sys.stdout.write(message + "\n") )[-1] say_hello() 

However, it's not possible to use either of these in your example because your variable flag is in an outer scope, not the lambda's scope. This doesn't have to do with lambda, it's the general behaviour in Python 2. Python 3 lets you get around this with the nonlocal keyword inside of defs, but nonlocal can't be used inside lambdas.

There's a workaround (see below), but while we're on the topic...


In some cases you can use this to do everything inside of a lambda:

(lambda: [     ['def'         for sys in [__import__('sys')]         for math in [__import__('math')]          for sub in [lambda *vals: None]         for fun in [lambda *vals: vals[-1]]          for echo in [lambda *vals: sub(             sys.stdout.write(u" ".join(map(unicode, vals)) + u"\n"))]          for Cylinder in [type('Cylinder', (object,), dict(             __init__ = lambda self, radius, height: sub(                 setattr(self, 'radius', radius),                 setattr(self, 'height', height)),              volume = property(lambda self: fun(                 ['def' for top_area in [math.pi * self.radius ** 2]],                  self.height * top_area))))]          for main in [lambda: sub(             ['loop' for factor in [1, 2, 3] if sub(                 ['def'                     for my_radius, my_height in [[10 * factor, 20 * factor]]                     for my_cylinder in [Cylinder(my_radius, my_height)]],                  echo(u"A cylinder with a radius of %.1fcm and a height "                      u"of %.1fcm has a volume of %.1fcm³."                      % (my_radius, my_height, my_cylinder.volume)))])]],      main()])() 

A cylinder with a radius of 10.0cm and a height of 20.0cm has a volume of 6283.2cm³.
A cylinder with a radius of 20.0cm and a height of 40.0cm has a volume of 50265.5cm³.
A cylinder with a radius of 30.0cm and a height of 60.0cm has a volume of 169646.0cm³.

Please don't.


...back to your original example: though you can't perform assignments to the flag variable in the outer scope, you can use functions to modify the previously-assigned value.

For example, flag could be an object whose .value we set using setattr:

flag = Object(value=True) input = [Object(name=''), Object(name='fake_name'), Object(name='')]  output = filter(lambda o: [     flag.value or bool(o.name),     setattr(flag, 'value', flag.value and bool(o.name)) ][0], input) 
[Object(name=''), Object(name='fake_name')] 

If we wanted to fit the above theme, we could use a list comprehension instead of setattr:

    [None for flag.value in [bool(o.name)]] 

But really, in serious code you should always use a regular function definition instead of a lambda if you're going to be doing outer assignment.

flag = Object(value=True) def not_empty_except_first(o):     result = flag.value or bool(o.name)     flag.value = flag.value and bool(o.name)     return result input = [Object(name=""), Object(name="fake_name"), Object(name="")]  output = filter(not_empty_except_first, input) 
like image 87
Jeremy Avatar answered Oct 13 '22 04:10

Jeremy