どのようにしてラムダ式を記述できますか?
def x():
raise Exception()
以下は許可されていません。
y = lambda : raise Exception()
y=lambda...何def y:でしょうか?
どのようにしてラムダ式を記述できますか?
def x():
raise Exception()
以下は許可されていません。
y = lambda : raise Exception()
y=lambda...何def y:でしょうか?
回答:
Pythonのスキンを作成する方法は複数あります。
y = lambda: (_ for _ in ()).throw(Exception('foobar'))
ラムダはステートメントを受け入れます。raise exはステートメントなので、次のように汎用のレイザーを作成できます。
def raise_(ex):
raise ex
y = lambda: raise_(Exception('foobar'))
しかし、あなたの目標がを避けることであるならdef、これは明らかにそれを切りません。ただし、条件付きで例外を発生させることはできます。例:
y = lambda x: 2*x if x < 10 else raise_(Exception('foobar'))
または、名前付き関数を定義せずに例外を発生させることもできます。必要なのは強いお腹(そして与えられたコードでは2.x)だけです。
type(lambda:0)(type((lambda:0).func_code)(
1,1,1,67,'|\0\0\202\1\0',(),(),('x',),'','',1,''),{}
)(Exception())
そしてpython3の強力な胃液:
type(lambda: 0)(type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b''),{}
)(Exception())
どの例外が発生してもかまわない場合の非常に単純な答えを指摘してくれた@WarrenSpencerに感謝しますy = lambda: 1/0。
lambda: 1 / 0。通常の例外の代わりにZeroDivisionErrorがスローされるだけです。例外の伝播が許可されている場合、コードをデバッグしている誰かが一連のZeroDivisionErrorsを見始めるのは奇妙に見えるかもしれないことを覚えておいてください。
y = 1/0例外タイプが無関係である場合は、非常にスマートなソリューションです
どうですか:
lambda x: exec('raise(Exception(x))')
SyntaxError。Python2.7.11を使用しています。
実は方法はありますが、かなり工夫されています。
compile()組み込み関数を使用してコードオブジェクトを作成できます。これにより、raiseステートメント(またはそのほかのステートメント)を使用できますが、コードオブジェクトの実行という別の課題が生じます。通常の方法はexecステートメントを使用することですが、それによって元の問題に戻ります。つまり、ステートメントをa lambda(または)で実行できないということですeval()。
解決策はハックです。lambdaステートメントの結果などの呼び出し可能オブジェクトには、__code__実際には置き換え可能な属性があります。したがって、呼び出し可能オブジェクトを作成__code__し、その値を上記のコードオブジェクトで置き換えると、ステートメントを使用せずに評価できるものが得られます。ただし、これをすべて実現すると、非常にあいまいなコードになります。
map(lambda x, y, z: x.__setattr__(y, z) or x, [lambda: 0], ["__code__"], [compile("raise Exception", "", "single"])[0]()
上記は次のことを行います。
compile()呼び出しが例外を発生させるコードオブジェクトを作成します。
lambda: 0戻り何もしないが、値0を返す呼び出し可能-これは、後で上記のコードオブジェクトを実行するために使用されます。
これlambda x, y, zにより__setattr__、残りの引数を使用して最初の引数のメソッドを呼び出し、最初の引数を返す関数が作成されます。__setattr__それ自体がを返すため、これは必要Noneです。
map()呼び出しが結果を受け取りlambda: 0、そして使用してlambda x, y, z置き換え、それの__code__結果を持つオブジェクトcompile()の呼び出しを。このマップ操作の結果は、によって返される1つのエントリを持つリストlambda x, y, zです。これが必要な理由です。すぐにlambda使用する__setattr__と、lambda: 0オブジェクトへの参照が失われます。
最後に、map()呼び出しによって返されたリストの最初の(そして唯一の)要素が実行され、コードオブジェクトが呼び出され、最終的に必要な例外が発生します。
動作しますが(Python 2.6でテスト済み)、間違いなくきれいではありません。
最後に、typesモジュールへのアクセス権がある場合(のimport前のステートメントを使用する必要がありますeval)、このコードを少し短くするtypes.FunctionType()ことができます。これを使用すると、特定のコードオブジェクトを実行する関数を作成できるため、ダミー関数を作成してlambda: 0その__code__属性の値を置き換えるハックは必要ありません。
ラムダフォームで作成された関数にステートメントを含めることはできません。
必要なのが任意の例外を発生させるラムダ式である場合は、不正な式でこれを実現できます。たとえばlambda x: [][0]、空のリストの最初の要素にアクセスしようとすると、IndexErrorが発生します。
注意:これはハッキングであり、機能ではありません。しない別の人間が参照するか、使用する可能性のある任意の(非コードゴルフ)のコードでこれを使用しています。
TypeError: <lambda>() takes exactly 1 positional argument (2 given)。IndexErrorを確認しますか?
lambda *x: [][0]。(元のバージョンは1つの引数のみを受け取ります。引数がない場合は、を使用しlambda : [][0]、2つの場合はlambda x,y: [][0];などを使用します)
lambda x: {}["I want to show this message. Called with: %s" % x] : KeyError: 'I want to show this message. Called with: foo'
Marcelo Cantosが提供した回答のUPDATE 3について説明します。
type(lambda: 0)(type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b''),{}
)(Exception())
lambda: 0builtins.functionクラスのインスタンスです。
type(lambda: 0)あるbuiltins.functionクラスでは。
(lambda: 0).__code__あるcodeオブジェクトが。オブジェクトは、他のものの間でコンパイルされたバイトコードを保持するオブジェクトです。これは、ここCPython https://github.com/python/cpython/blob/master/Include/code.hで定義されています。そのメソッドはここhttps://github.com/python/cpython/blob/master/Objects/codeobject.cに実装されています。コードオブジェクトに対してヘルプを実行できます。code
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__)コードクラスです。
だから私たちが言うとき
type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b'')
次の引数を使用して、コードオブジェクトのコンストラクターを呼び出します。
引数の意味については、PyCodeObject
https://github.com/python/cpython/blob/master/Include/code.hの定義を参照してください。flags引数の67の値は、たとえばCO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREEです。
最も重要な引数は、codestring命令オペコードを含むものです。それらの意味を見てみましょう。
>>> import dis
>>> dis.dis(b'|\0\202\1\0')
0 LOAD_FAST 0 (0)
2 RAISE_VARARGS 1
4 <0>
オペコードのドキュメントは、https: //docs.python.org/3.8/library/dis.html#python-bytecode-instructionsにあり
ます。最初のバイトはのオペコードでLOAD_FAST、2番目のバイトはその引数、つまり0です。
LOAD_FAST(var_num)
Pushes a reference to the local co_varnames[var_num] onto the stack.
参照をxスタックにプッシュします。これvarnamesは、「x」のみを含む文字列のリストです。定義している関数の唯一の引数をスタックにプッシュします。
次のバイトはのオペコードでRAISE_VARARGS、次のバイトはその引数、つまり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)
TOSはスタックのトップです。x関数の最初の引数()をスタックにプッシュし、1であるargcため、
xそれが例外インスタンスである場合は発生させ、またはのインスタンスを作成しxてそれ以外の場合は発生させます。
最後のバイト、つまり0は使用されません。有効なオペコードではありません。そこにないかもしれません。
コードスニペットに戻ります。
type(lambda: 0)(type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b''),{}
)(Exception())
コードオブジェクトのコンストラクターを呼び出しました。
type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b'')
コードオブジェクトと空の辞書を関数オブジェクトのコンストラクターに渡します。
type(lambda: 0)(type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b''),{}
)
関数オブジェクトのヘルプを呼び出して、引数の意味を見てみましょう。
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
次に、構築された関数を呼び出し、Exceptionインスタンスを引数として渡します。その結果、例外を発生させるラムダ関数を呼び出しました。スニペットを実行して、実際に意図したとおりに機能することを確認しましょう。
>>> 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
バイトコードの最後のバイトは役に立たないことがわかりました。この複雑な表現を針で乱雑にしましょう。そのバイトを削除しましょう。また、少しゴルフをしたい場合は、Exceptionのインスタンス化を省略して、代わりにExceptionクラスを引数として渡すことができます。これらの変更により、次のコードが生成されます。
type(lambda: 0)(type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1',(),(),('x',),'','',1,b''),{}
)(Exception)
実行すると、以前と同じ結果が得られます。ただ短いだけです。