203

How can I write a lambda expression that's equivalent to:

def x():
    raise Exception()

The following is not allowed:

y = lambda : raise Exception()
Thomas Jung
  • 32,428
  • 9
  • 84
  • 114
  • 6
    So you can't do that. Use normal functions. – DrTyrsa Nov 28 '11 at 10:43
  • 2
    What is the point of giving a name to an anonymous function? – John La Rooy Nov 28 '11 at 11:12
  • 3
    @gnibbler You can use the name to refer to the function. y() is easier to use than (lambda : 0)() in the REPL. – Thomas Jung Nov 28 '11 at 11:56
  • 2
    So what is the advantage of `y=lambda...` over `def y:` then? – John La Rooy Nov 28 '11 at 22:23
  • 1
    @gnibbler Some context: I wanted to define a function def g(f, e) that calls f in the happy case and e if an error was detected. Depending on the scenario e could raise an exception or return some valid value. To use g I wanted to write g(lambda x: x *2, lambda e: raise e) or alternatively g(lambda x: x * 2, lambda e : 0). – Thomas Jung Nov 29 '11 at 07:18
  • Just in case anyone else comes here looking for a way to raise an exception as part of a pytest monkeypatch (or equivalent), I ended up using the monkeypatch to hit a fixture that used the side_effect argument to Mock like this: `def mock_urlopen(): return Mock(spec=urllib2.urlopen, side_effect=urllib2.URLError('Fake URLError Exception'))` – Dave Gregory Aug 19 '15 at 17:05
  • If you reached here since you want to raise an exception in a mock, then use: [side_effect()](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.side_effect) – guettli May 03 '21 at 14:28
  • @JohnLaRooy For posterity, there is none. [Named lambdas are bad practice](/q/38381556/4518341). Use a `def` instead. – wjandrea Oct 15 '21 at 03:54

9 Answers9

251

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.

Neuron
  • 5,141
  • 5
  • 38
  • 59
Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
  • 209
    OMG what dark art it is? –  Dec 05 '14 at 06:55
  • 28
    If you don't care what type of exception is thrown, the following also works: `lambda: 1 / 0`. You'll just end up with a ZeroDivisionError being thrown instead of a regular exception. Bear in mind that if the exception is allowed to propogate, it may look strange to someone debugging your code to start seeing a bunch of ZeroDivisionErrors. – Warren Spencer Sep 20 '16 at 13:09
  • Great solution @WarrenSpencer. Most code doesn't have a lot of zero division errors, so it's as distinctive as if you could choose the type yourself. – jwg Sep 29 '17 at 15:11
  • 1
    @WarrenSpencer great suggestion! I've added it to the answer. – Marcelo Cantos Oct 01 '17 at 19:55
  • 4
    `y = 1/0` is super smart solution if Exception type is irrelevant – Saher Ahwal May 25 '18 at 01:03
  • 16
    Can anyone talk us through what is actually going on in the 'dark-art/strong stomach' solutions? – decvalts May 01 '19 at 16:43
  • Like the Update 2 most. #SkinThePython ! – RayLuo Oct 19 '19 at 18:34
  • 4
    The 'strong stomach' solution is some awesome code golf! For details search for bytecode in Google and in a notebook `help(type(lambda: 0)) `and `help((lambda: 0).__code__)` and look at the module `dis`. There are two cool parts. The builtin classes `function` and `code` are not exposed, else it would be `function(code( 13 arguments),{})(Exception)`. `lambda: 0` just returns a `function` instance, for which we need the class, hence the `type(lambda: 0)`. An alternative is `(lambda:0).__class__`. `help(code)` and `dis` explain 13 args, but `b'|\0\202\1\0'` is the bytecode string, see `compile` – Matteo Ferla Jan 29 '21 at 12:12
  • Tagging on to @WarrenSpencer's approach, `lambda: n` works as long as you can ensure that `n` is not defined in the scope where the lambda is defined (you raise `NameError` this way). Even defining `n` in the scope where the lambda is *used* doesn't prevent the exception (if that's a different scope). – Karl Knechtel Nov 08 '21 at 18:14
  • 3
    I guess you could also do `lambda: [][1]` for an `IndexError`, `lambda: {}['']` for `KeyError`, `lambda: ''+0` for `TypeError` etc. – Karl Knechtel Nov 08 '21 at 18:26
87

How about:

lambda x: exec('raise(Exception(x))')
Michael Mrozek
  • 169,610
  • 28
  • 168
  • 175
vvkatwss vvkatwss
  • 3,345
  • 1
  • 21
  • 24
  • 16
    It is quite hacky but for writing tests where you want to mock functions this works neat !!! – Kannan Ekanath May 03 '13 at 10:14
  • 21
    Works but you shouldn't do it. – augurar Apr 17 '15 at 19:40
  • 1
    This doesn't work for me, I get a `SyntaxError` on Python 2.7.11. – Nick Sweeting Feb 26 '16 at 08:44
  • I am also getting the above error (SyntaxError) on Python 2.7.5 – Dinesh Jan 26 '18 at 13:16
  • This works with Python 3.6. Maybe to file a bug to Python 2.7.5? – vvkatwss vvkatwss Jan 31 '18 at 15:12
  • 1
    this is specific to python 3 however I don't think python 2 allows that. – Saher Ahwal May 25 '18 at 01:14
  • 1
    @kannanEkanath , you called this hacky? Comparing to the currently most-upvoted and accepted answer, this answer feels like a breeze. It at least uses the `exec()` in its expected way. I've upvoted this answer. It is just unfortunate that it does not work in Python 2. – RayLuo Oct 19 '19 at 18:32
  • 19
    @augurar Why should we not use this solution? If it's because `exec()` is dangerous, is that even relevant here when the argument to `exec()` is hard-coded? If I have enough access to the code base to change that string, then adding a line above to read `import os; os.system('destroy all the things')` would be just as easy. Is there another reason I don't know of why you're recommending against this? Textbooks always stop at "Just don't", which doesn't help anyone understand the possible dangers. – JDG Nov 21 '20 at 01:54
  • True, this looks really good and I will probably use it. I'm guessing people are saying not to because of the ability of the exec function, but not necessarily this use of it. – Break Jan 26 '21 at 23:22
32

I'd like to give an explanation of the UPDATE 3 of the answer provided by Marcelo Cantos:

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

Explanation

lambda: 0 is an instance of the builtins.function class.
type(lambda: 0) is the builtins.function class.
(lambda: 0).__code__ is a code object.
A code object is an object which holds the compiled bytecode among other things. It is defined here in CPython https://github.com/python/cpython/blob/master/Include/code.h. Its methods are implemented here https://github.com/python/cpython/blob/master/Objects/codeobject.c. We can run the help on the code object:

Help on code object:

class code(object)
 |  code(argcount, kwonlyargcount, nlocals, stacksize, flags, codestring,
 |        constants, names, varnames, filename, name, firstlineno,
 |        lnotab[, freevars[, cellvars]])
 |  
 |  Create a code object.  Not for the faint of heart.

type((lambda: 0).__code__) is the code class.
So when we say

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

we are calling the constructor of the code object with the following arguments:

  • argcount=1
  • kwonlyargcount=0
  • nlocals=1
  • stacksize=1
  • flags=67
  • codestring=b'|\0\202\1\0'
  • constants=()
  • names=()
  • varnames=('x',)
  • filename=''
  • name=''
  • firstlineno=1
  • lnotab=b''

You can read about what the arguments mean in the definition of the PyCodeObject https://github.com/python/cpython/blob/master/Include/code.h. The value of 67 for the flags argument is for example CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE.

The most importand argument is the codestring which contains instruction opcodes. Let's see what they mean.

>>> import dis
>>> dis.dis(b'|\0\202\1\0')
          0 LOAD_FAST                0 (0)
          2 RAISE_VARARGS            1
          4 <0>

The documentation of opcodes can by found here https://docs.python.org/3.8/library/dis.html#python-bytecode-instructions. The first byte is the opcode for LOAD_FAST, the second byte is its argument i.e. 0.

LOAD_FAST(var_num)
    Pushes a reference to the local co_varnames[var_num] onto the stack.

So we push the reference to x onto the stack. The varnames is a list of strings containing only 'x'. We will push the only argument of the function we are defining to the stack.

The next byte is the opcode for RAISE_VARARGS and the next byte is its argument i.e. 1.

RAISE_VARARGS(argc)
    Raises an exception using one of the 3 forms of the raise statement, depending on the value of argc:
        0: raise (re-raise previous exception)
        1: raise TOS (raise exception instance or type at TOS)
        2: raise TOS1 from TOS (raise exception instance or type at TOS1 with __cause__ set to TOS)

The TOS is the top-of-stack. Since we pushed the first argument (x) of our function to the stack and argc is 1 we will raise the x if it is an exception instance or make an instance of x and raise it otherwise.

The last byte i.e. 0 is not used. It is not a valid opcode. It might as well not be there.

Going back to code snippet we are anylyzing:

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

We called the constructor of the code object:

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

We pass the code object and an empty dictionary to the constructor of a function object:

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

Let's call help on a function object to see what the arguments mean.

Help on class function in module builtins:

class function(object)
 |  function(code, globals, name=None, argdefs=None, closure=None)
 |  
 |  Create a function object.
 |  
 |  code
 |    a code object
 |  globals
 |    the globals dictionary
 |  name
 |    a string that overrides the name from the code object
 |  argdefs
 |    a tuple that specifies the default argument values
 |  closure
 |    a tuple that supplies the bindings for free variables

We then call the constructed function passing an Exception instance as an argument. Consequently we called a lambda function which raises an exception. Let's run the snippet and see that it indeed works as intended.

>>> type(lambda: 0)(type((lambda: 0).__code__)(
...     1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b''),{}
... )(Exception())
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
  File "", line 1, in 
Exception

Improvements

We saw that the last byte of the bytecode is useless. Let's not clutter this complicated expression needlesly. Let's remove that byte. Also if we want to golf a little we could omit the instantiation of Exception and instead pass the Exception class as an argument. Those changes would result in the following code:

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

When we run it we will get the same result as before. It's just shorter.

katsu
  • 604
  • 6
  • 7
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.

Michael Scarpa
  • 191
  • 1
  • 2
17

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.

Neuron
  • 5,141
  • 5
  • 38
  • 59
Kyle Strand
  • 15,941
  • 8
  • 72
  • 167
  • In my case I get: `TypeError: () takes exactly 1 positional argument (2 given)`. Are you sure of the IndexError? – Jovik Jan 24 '13 at 16:27
  • 4
    Yep. Did you perhaps provide the wrong number of arguments? If you need a lambda function that can take any number of arguments, use `lambda *x: [][0]`. (The original version only takes one argument; for no arguments, use `lambda : [][0]`; for two, use `lambda x,y: [][0]`; etc.) – Kyle Strand Jan 24 '13 at 23:21
  • 6
    I've expanded this a little: `lambda x: {}["I want to show this message. Called with: %s" % x]` Produces: `KeyError: 'I want to show this message. Called with: foo'` – ErlVolton Oct 14 '14 at 15:37
  • @ErlVolton Clever! Though using this anywhere except in a one-off script seems like a terrible idea... – Kyle Strand Oct 14 '14 at 16:01
  • I'm temporarily using in unit tests for a project where I haven't bothered to make a real mock of my logger. It raises if you try to log an error or critical. So... Yes terrible, although consensual :) – ErlVolton Oct 14 '14 at 18:39
  • This is actually great, no messy code and raises random exception - so unless I need to raise a specific one, this is good. – Tomáš Zato Sep 07 '15 at 17:02
  • @TomášZato Again, I wouldn't recommend this for production code. Keep in mind that someone else will at some point need to maintain the code, so even if you catch the exception yourself, someone will still at some point look at this and wonder what on earth is going on. A comment might help, but Python should typically be self-documenting. So consider defining an actual function instead which throws a specific exception. – Kyle Strand Sep 07 '15 at 17:22
  • @KyleStrand Who said something about production code? I just wanted to check what happens when XMLRPCServer function throws error - whether client sees it or server crashes. – Tomáš Zato Sep 07 '15 at 17:23
  • That sounds like a perfect use of this "hack" :) – Kyle Strand Sep 07 '15 at 17:27
  • You don't need that `x`. Just `lambda: [][0]` would do. But then if we are heading to this direction, I would rather do `lambda:1/0` which is at least shorter, when everything else is being equal ... I mean equally bad for readability. :-) – RayLuo Oct 19 '19 at 18:23
  • @RayLuo You need however many arguments are required by the context, of course. See my comment above. – Kyle Strand Oct 20 '19 at 18:30
15

Functions created with lambda forms cannot contain statements.

Mitar
  • 6,756
  • 5
  • 54
  • 86
  • 4
    This is true, but it doesn't really answer the question; raising an exception from a lambda expression is easy to do (and catching it may sometimes be achieved by using very contrived tricks, see https://stackoverflow.com/a/50916686/2560053 or https://stackoverflow.com/a/50961836/2560053 ). – Thomas Baruchel Jun 21 '18 at 06:39
9

Every time I have wanted to do this, it was in a test where I wanted to assert that a function was not called.

For this use case, I found it clearer to use a mock with a side effect

from unittest.mock import Mock
MyClass.my_method = Mock(side_effect=AssertionError('we should not reach this method call')

It would also work in other settings, but I'd rather not depend on unittest in my main application

Atn
  • 521
  • 4
  • 14
9

All the solutions above do work but I think this one is the shortest in case you just need any function that raises a random exception:

lambda: 0/0

et voila!

Nadhem Maaloul
  • 433
  • 5
  • 11
0

You can do a simple invalid operation in your Lambda function that results in the desired exception:

>>> (1).a
AttributeError: 'int' object has no attribute 'a'

>>> [][1]
IndexError: list index out of range

>>> {}['']
KeyError: ''

# this one can even hold a custom text
>>> {}['use foo or bar']
KeyError: 'use foo or bar'

>>> ''+0
TypeError: can only concatenate str (not "int") to str

>>> 1/0
ZeroDivisionError: division by zero

Use it like lambda: <operation>, e.g. lambda: 1/0.


This answer is based on Saher Ahwal’s and Karl Knechtel’s comments. It’s a Community Wiki post, feel free to extend the list above.

Melebius
  • 6,183
  • 4
  • 39
  • 52