定义引发exception的lambdaexpression式
我怎样才能写一个等同于下面的lambdaexpression式?
def x(): raise Exception()
以下是不允许的:
y = lambda : raise Exception()
更新2:我错了! 事实certificate,有不止一种方式来皮肤的Python:
y = lambda: (_ for _ in ()).throw(Exception('foobar'))
不,兰姆达斯只接受expression。 raise ex
是一个声明。 当然,你可以写一个通用的提升者:
def raise_(ex): raise ex y = lambda: raise_(Exception('foobar'))
但如果你的目标是避免def
,这显然不会削减它。 不过,它可以让你有条件地提出exception,例如:
y = lambda x: 2*x if x < 10 else raise_(Exception('foobar'))
更新:好的,所以你可以引发一个exception,而不需要定义一个命名函数。 所有你需要的是一个强大的胃(和2.x给定的代码):
type(lambda:0)(type((lambda:0).func_code)( 1,1,1,67,'|\0\0\202\1\0',(),(),('x',),'','',1,''),{} )(Exception())
更新3:和python3 强大的胃解决scheme:
type(lambda: 0)(type((lambda: 0).__code__)( 1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b''),{} )(Exception())
更新4:谢谢@WarrenSpencer指出一个非常简单的答案,如果你不在乎引发了哪个exception: y = lambda: 1/0
。
怎么样:
lambda x: exec('raise(Exception(x))')
实际上,有一个办法,但是很有人气。
您可以使用compile()
内置函数创build一个代码对象。 这允许你使用raise
语句(或者任何其他语句),但是它提出了另一个挑战:执行代码对象。 通常的方法是使用exec
语句,但这导致你回到原来的问题,即你不能在一个lambda
(或eval()
,执行语句)。
解决scheme是一个黑客。 象lambda
语句的结果__code__
,可加__code__
都有一个属性__code__
,它可以被replace。 所以,如果你创build了一个可调用的对象,并用上面的代码对象replace它的__code__
值,那么你可以得到一些不需要使用语句就可以评估的东西。 实现这一切,但是,导致非常模糊的代码:
map(lambda x, y, z: x.__setattr__(y, z) or x, [lambda: 0], ["__code__"], [compile("raise Exception", "", "single"])[0]()
以上做了以下工作:
-
compile()
调用会创build一个引发exception的代码对象; -
lambda: 0
返回一个可调用的函数,它什么也不做,只是返回值0 – 这个被用来稍后执行上面的代码对象; -
lambda x, y, z
创build一个函数,用其余参数调用第一个参数的__setattr__
方法,并返回第一个参数! 这是必要的,因为__setattr__
本身返回None
; -
map()
调用的结果是lambda: 0
,并且使用lambda x, y, z
将__code__
compile()
调用的结果replace为__code__
对象。 这个映射操作的结果是一个列表,只有一个条目,由lambda x, y, z
,这就是为什么我们需要这个lambda
:如果我们马上使用__setattr__
,我们将失去对lambda: 0
的引用lambda: 0
目的! -
最后,执行
map()
调用返回的列表的第一个(也是唯一的)元素,导致调用代码对象,最终引发所需的exception。
它工作(在Python 2.6中testing),但它绝对不漂亮。
最后一个注意:如果你有权访问types
模块(在你的eval
之前需要使用import
语句),那么你可以缩短这个代码:using types.FunctionType()
你可以创build一个函数来执行给定的代码对象,所以你不需要用lambda: 0
创build一个虚拟函数,并replace它的__code__
属性的值。
如果你想要的只是一个引发任意exception的lambdaexpression式,你可以用一个非法的expression来完成。 例如, lambda x: [][0]
将尝试访问空列表中的第一个元素,这将引发IndexError。
请注意 :这是一个黑客,而不是一个function。 不要使用这是另一个人可能会看到或使用的任何(非代码高尔夫)代码。
用lambda表单创build的函数不能包含语句 。