1

Suppose I have the following python list:

my_list = [1, 2,'X', 'Y', 0]

Suppose I want to copy values of this list into a new list as follows:

  1. If it is a digit between 0-9, copy that value into the new list
  2. ElIf it is 'X', copy None into the new list
  3. Else raise an Exception

Can I do it with a lambda function as shown below? If so, how?

new_list = map(lambda(x): something-here-but-what??, my_list)
Saqib Ali
  • 11,931
  • 41
  • 133
  • 272
  • Did you try it? Did it work? – wwii Oct 14 '17 at 05:09
  • No. Obviously the phrase `something-here-but-what??` will never work. – Saqib Ali Oct 14 '17 at 05:13
  • 1
    maybe with a convoluted [conditional expression](https://docs.python.org/3/reference/expressions.html#conditional-expressions) and some of the ideas in [this SO Q&A](https://stackoverflow.com/questions/8294618/define-a-lambda-expression-that-raises-an-exception) – wwii Oct 14 '17 at 05:16
  • I think this is a valid question, but it is rather unpythonic which is probably why people are downvoting it. – zxq9 Oct 14 '17 at 05:31
  • See a related question: https://stackoverflow.com/questions/8294618/define-a-lambda-expression-that-raises-an-exception – supermitch May 08 '23 at 21:03

4 Answers4

2

Why not just write a function that does what you want and put it in the lambda? I don't see a reason to try to make a convoluted one-liner for something that should be more than one line.

my_list = [1, 2,'X', 'Y', 0]

def replace(x):
    if x == 'X':
        return None
    elif type(x) == int and x <= 9 and x >= 0:
        return x
    else:
        raise ValueError('Bad value')

new_list = map(lambda(x): replace(x), my_list[:-2]) # Returns [1, 2, None]
new_list = map(lambda(x): replace(x), my_list) # Raises exception
Brenden Petersen
  • 1,993
  • 1
  • 9
  • 10
  • I like short beautiful code. I was trying to resist writing a separate function. But I guess I will have to. – Saqib Ali Oct 14 '17 at 05:17
  • 2
    I, too, like short, beautiful code. But in this case, it would be short, ugly code ;-) I think having three conditionals calls for its own function. I find lambda more useful for things like creating a custom function on the fly that you might use later (`x = lambda ...`), not just because you don't want to name your function. Also, looking at link given by @wwii, it's *really* ugly to actually make a lambda throw an expression the way you originally intended. – Brenden Petersen Oct 14 '17 at 05:18
1

To back up Brenden's (quite correct) answer...

You can actually do some weird things with Python ternary expressions... but the result is just unbearable. Consider a partial solution:

>>> new_list = map(lambda x: x if isinstance(x, int) and (0 <= x and x <= 9) else ValueError('Bad things happened'), [1, 2, 3, "blah"])
>>> list(new_list)
[1, 2, 3, ValueError('Bad things happened',)]

Not only is that horrid and would probably confuse most Pythonistas (not just the use of an unusual construction, but why would you use this construction?), I don't know quite what to do yet about actually raising the exception right there without redefining the way list() works. (raise only works when it is standing alone.)

So now we have a confusing lambda that conditionally permits a member into the new map construction or includes a ValueError object instead. Yuk.

Much better to abstract this whole idea away behind a function that does, in a very simple way, exactly what you want -- and let the "beautiful code part" be the bit people will normally need to read in the future that goes something like:

new_list = valid_list_to_map(your_list)
zxq9
  • 13,020
  • 1
  • 43
  • 60
1

Use a conditional expression.

a = list(map(lambda n: n if n in (0,1,2,3,4,5,6,7,8,9) else (None if n == 'X' else 1/0), my_list))

Other exceptions that can be raised:
In the conditional expression replace 1/0 with

{}[n]                                       #KeyError
x                                           #NameError 
(_ for _ in ()).throw(Exception('Foo')))    #any kind of exception you want
int('x')                                    #ValueError
wwii
  • 23,232
  • 7
  • 37
  • 77
0

To raise an exception you have to use 'try' and 'except' statement and Statements are not allowed in the lambda expression. In the Lambda expression, you can only have expressions so you can't raise the exception in the lambda function.

Gome
  • 131
  • 3
  • No, you can `raise` anywhere -- it just doesn't stand much chance of getting caught by anything if you don't write your own `try .. except`. Sometimes crashing the program is the right thing to do, hence the construction. (Actually, being primarily an Erlang programmer I tend to believe that crashing the program is almost always the right thing to do, but that's a whole different world...) – zxq9 Oct 14 '17 at 05:34