dis.dis의 출력을 어떻게 이해해야합니까?
dis (파이썬 바이트 코드의 분해자) 를 사용하는 방법을 이해하고 싶습니다 . 특히 (또는 ) 의 출력을 어떻게 해석해야 우리 합니까?dis.dis
dis.disassemble
.
다음은 매우 구체적인 예입니다 (Python 2.7.3).
dis.dis("heapq.nsmallest(d,3)")
0 BUILD_SET 24933
3 JUMP_IF_TRUE_OR_POP 11889
6 JUMP_FORWARD 28019 (to 28028)
9 STORE_GLOBAL 27756 (27756)
12 LOAD_NAME 29811 (29811)
15 STORE_SLICE+0
16 LOAD_CONST 13100 (13100)
19 STORE_SLICE+1
JUMP_IF_TRUE_OR_POP
등이 바이트 코드 명령 이라는 것을 알았습니다 (흥미롭게 BUILD_SET
도이 목록에는 있지만 )BUILD_TUPLE
. 에있는 숫자 오른쪽는 메모리 할당이고 왼쪽에있는 숫자 는 고토 숫자라고 생각합니다. 매번 거의 3 씩 증가합니다 (정말 아님).
dis.dis("heapq.nsmallest(d,3)")
내부를 내부면 :
def f_heapq_nsmallest(d,n):
return heapq.nsmallest(d,n)
dis.dis("f_heapq(d,3)")
0 BUILD_TUPLE 26719
3 LOAD_NAME 28769 (28769)
6 JUMP_ABSOLUTE 25640
9 <44> # what is <44> ?
10 DELETE_SLICE+1
11 STORE_SLICE+1
은 소스 코드 당신를 포함하는 문자열을 분해하려고하지만하여 해당 지원되지 않는을 구석으로 dis.dis
그것 (기능 참조 바이트 코드를 포함 것처럼 문자열 인수와 파이썬 2에서, 문자열을 취급 그것은 disassemble_string
에를dis.py
). 따라서 소스 코드를 바이트 코드로 잘못 해석하여 무의미한 출력이 표시됩니다.
파이썬 3에서는 dis.dis
문자열 인수 를 분해하기 전에 컴파일하는 상황이 다릅니다 .
Python 3.2.3 (default, Aug 13 2012, 22:28:10)
>>> import dis
>>> dis.dis('heapq.nlargest(d,3)')
1 0 LOAD_NAME 0 (heapq)
3 LOAD_ATTR 1 (nlargest)
6 LOAD_NAME 2 (d)
9 LOAD_CONST 0 (3)
12 CALL_FUNCTION 2
15 RETURN_VALUE
Python 2에서는 다음으로 전달하기 전에 코드를 직접 수행해야합니다 dis.dis
.
Python 2.7.3 (default, Aug 13 2012, 18:25:43)
>>> import dis
>>> dis.dis(compile('heapq.nlargest(d,3)', '<none>', 'eval'))
1 0 LOAD_NAME 0 (heapq)
3 LOAD_ATTR 1 (nlargest)
6 LOAD_NAME 2 (d)
9 LOAD_CONST 0 (3)
12 CALL_FUNCTION 2
15 RETURN_VALUE
숫자는 무엇을 의미합니까? 수 1
맨 왼쪽이 바이트 코드의 컴파일 소스 코드 라인 번호이다. 숫자는 opargs 입니다. 실제 바이트 코드를 살펴 보겠습니다.
>>> co = compile('heapq.nlargest(d,3)', '<none>', 'eval')
>>> co.co_code.encode('hex')
'6500006a010065020064000083020053'
바이트 코드의 시스템 0에서 oparg 65
를 사용하여 opcode를 LOAD_NAME
찾습니다 0000
. 그런 다음 (오프셋 3에서) 6a
opcode LOAD_ATTR
, 0100
oparg 등이 있습니다. opargs는 리틀 엔디안 순서 0100
번호 1입니다. 문서화되지 않은 opcode
모듈에는 각 opname
opcode에 대한 이름과 각 이름에 대한 opcode를 제공하는 테이블이 포함되어 있습니다 opmap
.
>>> opcode.opname[0x65]
'LOAD_NAME'
oparg의 의미는 오피 코드에 따라 달라지며 전체 이야기에 대한 당신은 CPython에 가상 머신의 구현 읽을 필요 에를ceval.c
. For LOAD_NAME
및 LOAD_ATTR
oparg는 co_names
코드 객체 의 속성에 대한 인덱스입니다 .
>>> co.co_names
('heapq', 'nlargest', 'd')
들어 LOAD_CONST
그것의 인덱스입니다 co_consts
코드 개체의 속성 :
>>> co.co_consts
(3,)
의 경우 CALL_FUNCTION
하위 바이트의 일반 인수 수와 상위 바이트의 키워드 인수 수를 사용하여 16 비트로 인코딩 된 함수에 전달할 인수의 수입니다.
인터넷 검색 중에 찾을 수 있도록 다른 질문에 대한 답변을 다시 게시 하고 있습니다 dis.dis()
.
위대한 Gareth Rees의 답변 을 완성 하기 위해 분해 된 바이트 코드의 출력을 설명하는 작은 열 단위 요약이 있습니다.
예를 들어 다음과 같은 함수가 있습니다.
def f(num):
if num == 42:
return True
return False
이것은 (Python 3.6)로 분해 될 수 있습니다 :
(1)|(2)|(3)|(4)| (5) |(6)| (7)
---|---|---|---|----------------------|---|-------
2| | | 0|LOAD_FAST | 0|(num)
|-->| | 2|LOAD_CONST | 1|(42)
| | | 4|COMPARE_OP | 2|(==)
| | | 6|POP_JUMP_IF_FALSE | 12|
| | | | | |
3| | | 8|LOAD_CONST | 2|(True)
| | | 10|RETURN_VALUE | |
| | | | | |
4| |>> | 12|LOAD_CONST | 3|(False)
| | | 14|RETURN_VALUE | |
각 열에는 특정 용도가 있습니다.
- 소스 코드 의 해당 줄 번호
- 선택적으로 실행 된 현재 명령어를 나타냅니다 ( 예 : 프레임 객체 에서 바이트 코드를 가져온 경우 ).
JUMP
이전 지침 에서이 지침 까지 가능한 것을 나타내는 레이블- 바이트 인덱스에 해당하는 바이트 코드 의 주소 (Python 3.6은 각 명령어에 2 바이트를 사용하기 때문에 2의 배수이지만 이전 버전에서는 다를 수 있음)
- 명령어 이름 ( opname 이라고도 함 ) 은
dis
모듈에 간략하게 설명되어 있으며 해당 구현은ceval.c
(CPython의 핵심 루프) 에서 찾을 수 있습니다. - 일부 상수 또는 변수를 가져오고, 스택을 관리하고, 특정 명령어로 점프하는 등 Python에서 내부적으로 사용하는 명령어 의 인수 (있는 경우)입니다.
- 인간 친화적 인 해석 지시 인수의
참고 URL : https://stackoverflow.com/questions/12673074/how-should-i-understand-the-output-of-dis-dis
'ProgramingTip' 카테고리의 다른 글
jquery의 데이터 속성에서 부울 데이터 검색 (0) | 2020.12.04 |
---|---|
$ HOME과 '~'(물결표)의 차이점은 무엇입니까? (0) | 2020.12.04 |
지연된 작업 순서를 어떻게 볼 수 있습니까? (0) | 2020.12.04 |
FileInputStream을 사용하는 것보다 BufferedInputStream을 사용하여 파일을 바이트 단위로 빠르게 읽는 이유는 무엇입니까? (0) | 2020.12.04 |
Python에서 고속 푸리에 변환 플로팅 (0) | 2020.12.04 |