Definir una expresión lambda que plantea una excepción.

¿Cómo puedo escribir una expresión lambda que sea equivalente a:

def x(): raise Exception() 

No está permitido lo siguiente:

 y = lambda : raise Exception() 

ACTUALIZACIÓN 2: ¡Estaba equivocado! Resulta que hay más de una forma de despellejar un Python:

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

No. Lambdas solo acepta expresiones. raise ex es una statement. Por supuesto, usted podría escribir un aumento de propósito general:

 def raise_(ex): raise ex y = lambda: raise_(Exception('foobar')) 

Pero si tu objective es evitar una def , esto obviamente no lo elimina. Sin embargo, sí le permite generar excepciones de forma condicional, por ejemplo:

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

ACTUALIZACIÓN: OK, para que pueda generar una excepción sin definir una función nombrada. Todo lo que necesitas es un estómago fuerte (y 2.x para el código dado):

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

ACTUALIZACIÓN 3: Y una solución de estómago fuerte de python3:

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

ACTUALIZACIÓN 4: Gracias a @WarrenSpencer por señalar una respuesta muy simple si no le importa qué excepción se genera: y = lambda: 1/0 .

Qué tal si:

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

En realidad, hay una manera, pero es muy artificial.

Puede crear un objeto de código utilizando la función incorporada compile() . Esto le permite usar la statement de raise (o cualquier otra statement, para el caso), pero plantea otro desafío: ejecutar el objeto de código. La forma habitual sería utilizar la sentencia exec , pero eso lo lleva de vuelta al problema original, es decir, que no puede ejecutar sentencias en un lambda (o en una eval() , para el caso).

La solución es un hack. Todos los callables, como el resultado de una statement lambda , tienen un atributo __code__ , que puede ser reemplazado. Por lo tanto, si crea un valor invocable y reemplaza su valor __code__ con el objeto de código de arriba, obtendrá algo que se puede evaluar sin usar declaraciones. Sin embargo, lograr todo esto resulta en un código muy oscuro:

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

Lo anterior hace lo siguiente:

  • la llamada compile() crea un objeto de código que genera la excepción;

  • lambda: 0 devuelve un llamable que no hace nada pero devuelve el valor 0; esto se usa para ejecutar el código anterior más adelante;

  • la lambda x, y, z crea una función que llama al método __setattr__ del primer argumento con los argumentos restantes, Y DEVUELVE EL PRIMER ARGUMENTO! Esto es necesario, porque __setattr__ devuelve None ;

  • la llamada map() toma el resultado de lambda: 0 , y al usar lambda x, y, z reemplaza su objeto __code__ con el resultado de la llamada compile() . El resultado de esta operación de mapa es una lista con una entrada, la que devuelve lambda x, y, z , por lo que necesitamos este lambda : si __setattr__ inmediato, perderíamos la referencia al lambda: 0 ¡objeto!

  • finalmente, se ejecuta el primer (y único) elemento de la lista devuelto por la llamada map() , lo que da como resultado que se llame al objeto de código, lo que finalmente genera la excepción deseada.

Funciona (probado en Python 2.6), pero definitivamente no es bonito.

Una última nota: si tiene acceso al módulo de types (que requeriría usar la statement de import antes de su eval ), entonces puede acortar este código un poco: utilizando types.FunctionType() puede crear una función que se ejecutará el objeto de código dado, por lo que no necesitará el truco de crear una función ficticia con lambda: 0 y reemplazar el valor de su atributo __code__ .

Las funciones creadas con formularios lambda no pueden contener sentencias .

Si todo lo que desea es una expresión lambda que genere una excepción arbitraria, puede lograr esto con una expresión ilegal. Por ejemplo, lambda x: [][0] intentará acceder al primer elemento en una lista vacía, lo que generará un IndexError.

TENGA EN CUENTA : Esto es un truco, no una característica. No utilice este código (que no sea de código de golf) que otro ser humano pueda ver o usar.