The Python Oracle

Define a lambda expression that raises an Exception

--------------------------------------------------
Hire the world's top talent on demand or became one of them at Toptal: https://topt.al/25cXVn
and get $2,000 discount on your first invoice
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Horror Game Menu Looping

--

Chapters
00:00 Define A Lambda Expression That Raises An Exception
00:17 Accepted Answer Score 271
01:17 Answer 2 Score 96
01:28 Answer 3 Score 19
03:35 Answer 4 Score 18
03:59 Thank you

--

Full question
https://stackoverflow.com/questions/8294...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python

#avk47



ACCEPTED ANSWER

Score 271


There is more than one way to skin a Python:

y = lambda: (_ for _ in ()).throw(Exception('foobar'))

Lambdas accept statements. Since raise ex is a statement, you could write a general purpose raiser:

def raise_(ex):
    raise ex

y = lambda: raise_(Exception('foobar'))

But if your goal is to avoid a def, this obviously doesn't cut it. It does, however allow you to conditionally raise exceptions, e.g.:

y = lambda x: 2*x if x < 10 else raise_(Exception('foobar'))

Alternatively you can raise an exception without defining a named function. All you need is a strong stomach (and 2.x for the given code):

type(lambda:0)(type((lambda:0).func_code)(
  1,1,1,67,'|\0\0\202\1\0',(),(),('x',),'','',1,''),{}
)(Exception())

And a python3 strong stomach solution:

type(lambda: 0)(type((lambda: 0).__code__)(
    1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b''),{}
)(Exception())

Thanks @WarrenSpencer for pointing out a very simple answer if you don't care which exception is raised: y = lambda: 1/0.




ANSWER 2

Score 96


How about using exec, a built-in function in Python 3?

lambda x: exec('raise(Exception(x))')



ANSWER 3

Score 19


Actually, there is a way, but it's very contrived.

You can create a code object using the compile() built-in function. This allows you to use the raise statement (or any other statement, for that matter), but it raises another challenge: executing the code object. The usual way would be to use the exec statement, but that leads you back to the original problem, namely that you can't execute statements in a lambda (or an eval(), for that matter).

The solution is a hack. Callables like the result of a lambda statement all have an attribute __code__, which can actually be replaced. So, if you create a callable and replace it's __code__ value with the code object from above, you get something that can be evaluated without using statements. Achieving all this, though, results in very obscure code:

map(lambda x, y, z: x.__setattr__(y, z) or x, [lambda: 0], ["__code__"], [compile("raise Exception", "", "single"])[0]()

The above does the following:

  • the compile() call creates a code object that raises the exception;

  • the lambda: 0 returns a callable that does nothing but return the value 0 -- this is used to execute the above code object later;

  • the lambda x, y, z creates a function that calls the __setattr__ method of the first argument with the remaining arguments, AND RETURNS THE FIRST ARGUMENT! This is necessary, because __setattr__ itself returns None;

  • the map() call takes the result of lambda: 0, and using the lambda x, y, z replaces it's __code__ object with the result of the compile() call. The result of this map operation is a list with one entry, the one returned by lambda x, y, z, which is why we need this lambda: if we would use __setattr__ right away, we would lose the reference to the lambda: 0 object!

  • finally, the first (and only) element of the list returned by the map() call is executed, resulting in the code object being called, ultimately raising the desired exception.

It works (tested in Python 2.6), but it's definitely not pretty.

One last note: if you have access to the types module (which would require to use the import statement before your eval), then you can shorten this code down a bit: using types.FunctionType() you can create a function that will execute the given code object, so you won't need the hack of creating a dummy function with lambda: 0 and replacing the value of its __code__ attribute.




ANSWER 4

Score 18


If all you want is a lambda expression that raises an arbitrary exception, you can accomplish this with an illegal expression. For instance, lambda x: [][0] will attempt to access the first element in an empty list, which will raise an IndexError.

PLEASE NOTE: This is a hack, not a feature. Do not use this in any (non code-golf) code that another human being might see or use.