예외를 발생시키는 람다 식 정의
다음과 같은 람다 식을 작성하려면 어떻게 해야 합니까?
def x():
raise Exception()
다음은 허용되지 않습니다.
y = lambda : raise Exception()
Python을 벗기는 방법은 여러 가지가 있습니다.
y = lambda: (_ for _ in ()).throw(Exception('foobar'))
람다는 진술을 받아들입니다. 때부터raise ex
일반적인 용도로 사용할 수 있는 문장입니다.
def raise_(ex):
raise ex
y = lambda: raise_(Exception('foobar'))
▁a,면피다▁is▁your한▁but를 피하는 것이라면,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())
그리고 파이썬3의 강력한 위장 솔루션:
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 x: exec('raise(Exception(x))')
마르셀로 칸토스가 제공한 답변의 업데이트 3에 대해 설명하고자 합니다.
type(lambda: 0)(type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b''),{}
)(Exception())
설명.
lambda: 0
는 의예다니의 입니다.builtins.function
학생들
type(lambda: 0)
는 것은입니다.builtins.function
학생들
(lambda: 0).__code__
입니다.code
물건.
A code
object는 컴파일된 바이트 코드를 포함하는 객체입니다.CPython https://github.com/python/cpython/blob/master/Include/code.h 에 정의되어 있습니다.이 방법은 https://github.com/python/cpython/blob/master/Objects/codeobject.c 에서 구현됩니다.코드 개체에 대한 도움말을 실행할 수 있습니다.
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'')
다음과 같은 인수를 사용하여 코드 개체의 생성자를 호출합니다.
- argcount=1
- kwonlyargcount=0
- nlocal=1
- 스택 크기=1
- flags=67
- codestring=b'|\0\202\1\0'
- 상수 = 상수
- names=sys
- varnames=sysx',)
- 파일 이름='
- name='
- 첫 번째 줄 no=1
- lnotab=b'
당신은 인수가 정의에서 의미하는 것에 대해 읽을 수 있습니다.PyCodeObject
https://github.com/python/cpython/blob/master/Include/code.h .67의 값은 다음과 같습니다.flags
는 예를 " 는수예다니입"입니다.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>
opcode에 대한 문서는 https://docs.python.org/3.8/library/dis.html#python-bytecode-instructions 에서 확인할 수 있습니다.첫 번째 바이트는 다음에 대한 작업 코드입니다.LOAD_FAST
0.0 바이트는 0.0 바이트입니다.
LOAD_FAST(var_num)
Pushes a reference to the local co_varnames[var_num] onto the stack.
그래서 우리는 다음에 대한 참조를 밀어넣습니다.x
층층이루어그varnames
는 'x'만 포함하는 문자열 목록입니다.정의하고 있는 함수의 유일한 인수를 스택에 푸시합니다.
다음 바이트는 다음에 대한 작업 코드입니다.RAISE_VARARGS
1. 리고다바인수다니. 즉, 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
에 대한 의 ) 및 ) 스에택대우리기능과의한▁)기능과▁to▁)▁ofargc
1 우리는 그것을 올릴 것입니다.x
인 경우나 .x
그렇지 않으면 키웁니다.
마지막 바이트(0)는 사용되지 않습니다.유효한 opcode가 아닙니다.없는 것이 좋을 수도 있습니다.
코드 스니펫으로 돌아가서 분석해 보겠습니다.
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
그런 다음 예외 인스턴스를 전달하는 구성된 함수를 인수로 호출합니다.결과적으로 예외를 발생시키는 람다 함수를 불렀습니다.이제 스니펫을 실행하여 실제로 의도한 대로 작동하는지 확인해 보겠습니다.
>>> 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
개선 사항
우리는 바이트코드의 마지막 바이트가 쓸모가 없다는 것을 보았습니다.이 복잡한 표정을 바늘방석으로 어지럽히지 맙시다.그 바이트를 제거합니다.또한 골프를 조금 치고 싶다면 예외의 인스턴스화를 생략하고 대신 예외 클래스를 인수로 통과시킬 수 있습니다.이러한 변경으로 인해 다음 코드가 생성됩니다.
type(lambda: 0)(type((lambda: 0).__code__)(
1,0,1,1,67,b'|\0\202\1',(),(),('x',),'','',1,b''),{}
)(Exception)
실행 시 이전과 동일한 결과를 얻을 수 있습니다.더 짧을 뿐입니다.
사실, 방법이 있지만, 그것은 매우 고안되었습니다.
는 다을사코생수있성다습을 할 수 있습니다.compile()
내장기 이렇게 하면 이기하능을 사용할 수 .raise
명령문(또는 다른 명령문)이지만 코드 개체 실행이라는 또 다른 문제를 제기합니다.은 일적인다같습다니음과방은을 하는 것입니다.exec
의 문제,즉 술진, . 당은진실수술행할습을신래의신것을은지▁aments▁in,▁statement▁state없다,▁but▁problem▁original즉▁that▁can▁you▁back'▁execute수t▁the▁to▁leads▁you,실▁namely할▁that행진의 문장을 실행할 수 없다는 문제로 돌아가게 합니다.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만 합니다. -- 은 나중에데됩니다. 만 0 반환하는값가반호환을니다합능출만▁0값다반니합환▁returns능을가▁that반able는호▁--하. 이것은 나중에 위의 코드 개체를 실행하는 데 사용됩니다.그자리의
lambda x, y, z
는 를호하함생성다니합수를는출라고 .__setattr__
인수가 첫 , ARGUTION이라는 이름의 나드메및서다인반환니!이것은 필요합니다, 왜냐하면__setattr__
으로 절로돌아다오저다를 합니다.None
;그자리의
map()
은 의결를호다니합출의 를 .lambda: 0
리고사용을 합니다.lambda x, y, z
그것을 대신합니다.__code__
▁of의 객체.compile()
호출합니다. 이 지도 작업의 결과는 하나의 항목이 있는 목록입니다. 반환된 항목은lambda x, y, z
그게 우리가 이것이 필요한 이유입니다.lambda
우리가 이면다한용을 한다면,__setattr__
당장, 우리는 그것에 대한 참조를 잃을 것입니다.lambda: 0
목적어!지으로그첫, ▁the그▁returned▁by▁list▁of)에 의해 반환된 목록의 첫 번째 (그리고 유일한) 요소입니다.
map()
호출이 실행되어 코드 개체가 호출되고 궁극적으로 원하는 예외가 발생합니다.
(Python 2.6에서 테스트) 작동하지만, 확실히 예쁘지 않습니다.
한 참고 사항: "에 수 있는 : "에 액세스할 수 있는 경우: "에 액세스할 수 있습니다.types
(import
의 앞신술 .eval
), 이 수 : 사용), 그런음 다 이 를 코 조 줄 수 있 다 니 습 일 : 사types.FunctionType()
객체를 할 수 에 더미 를 생성하는 하지 않습니다.lambda: 0
그것의 그고것가대것는체하치를의 값을 합니다.__code__
기여하다.
임의 예외를 발생시키는 람다 식만 원하는 경우 잘못된 식으로 이를 수행할 수 있습니다.를 들면 예를들어들.lambda x: [][0]
빈 목록의 첫 번째 요소에 액세스하려고 시도하여 인덱스 오류가 발생합니다.
참고:이것은 해킹이지 기능이 아닙니다.다른 사람이 보거나 사용할 수 있는 코드(비코드 골프)에는 이 코드를 사용하지 마십시오.
람다 형식으로 작성된 함수에는 문을 포함할 수 없습니다.
위의 모든 솔루션은 작동하지만 랜덤 예외를 발생시키는 기능이 필요할 경우를 대비하여 이 솔루션이 가장 짧다고 생각합니다.
lambda: 0/0
에트빌라!
제가 이것을 하고 싶을 때마다, 그것은 함수가 호출되지 않았다는 것을 주장하고 싶은 테스트에서였습니다.
이 사용 사례의 경우 부작용이 있는 모크를 사용하는 것이 더 명확하다는 것을 알게 되었습니다.
from unittest.mock import Mock
MyClass.my_method = Mock(side_effect=AssertionError('we should not reach this method call')
다른 설정에서도 작동하지만 기본 응용 프로그램에서 유니트 테스트에 의존하지 않습니다.
람다 함수에서 원하는 예외를 발생시키는 간단한 잘못된 연산을 수행할 수 있습니다.
>>> (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
럼사용처럼 합니다.lambda: <operation>
를 들어, 예를 들어, 기호입니다.lambda: 1/0
.
이 대답은 Saher Ahwal과 Karl Knechtel의 논평에 기초합니다.커뮤니티 위키 게시물입니다. 위의 목록을 자유롭게 확장하십시오.
언급URL : https://stackoverflow.com/questions/8294618/define-a-lambda-expression-that-raises-an-exception
'programing' 카테고리의 다른 글
Numpy를 사용하여 파생물을 어떻게 계산합니까? (0) | 2023.07.19 |
---|---|
파이썬에서 문자열을 타이틀 케이스로 변환하는 방법은 무엇입니까? (0) | 2023.07.19 |
Spring MockMvc 웹 응용 프로그램 컨텍스트에 모의 주입 (0) | 2023.07.19 |
python을 딕트하기 위한 URL 쿼리 매개 변수 (0) | 2023.07.19 |
날짜/시간별 판다 데이터 프레임 그룹 (0) | 2023.07.19 |