dis — Python 바이트코드 디스어셈블러

dis — Python 바이트코드 디스어셈블러

dis 모듈은 CPython 바이트코드를 디스어셈블해서 분석하는 것을 지원해요. 이 모듈이 입력으로 받는 CPython 바이트코드는 Include/opcode.h 파일에 정의되어 있고, 컴파일러와 인터프리터가 사용해요.

CPython 구현 세부 사항 — 바이트코드는 CPython 인터프리터의 구현 세부 사항이에요. Python 버전 사이에 바이트코드가 추가·제거·변경되지 않는다는 보장은 없어요. 이 모듈이 Python VM이나 Python 릴리스 간에 동작한다고 간주하면 안 돼요.

버전 3.6에서 변경: 각 명령마다 2바이트를 사용함. 이전에는 명령에 따라 바이트 수가 달랐음. 버전 3.10에서 변경: 점프·예외 처리·루프 명령의 인자가 이제 바이트 오프셋이 아니라 명령 오프셋임. 버전 3.11에서 변경: 일부 명령은 CACHE 명령 형태의 인라인 캐시 항목을 하나 이상 동반함. 이 명령들은 기본적으로 숨겨지지만, 모든 dis 유틸리티에 show_caches=True를 전달하면 표시할 수 있음. 또한 인터프리터가 이제 바이트코드를 적응(adapt)시켜 다양한 런타임 조건에 특화함. 적응된 바이트코드는 adaptive=True를 전달하면 표시할 수 있음. 버전 3.12에서 변경: 점프의 인자는 점프 명령의 CACHE 항목 바로 뒤에 오는 명령에 상대적인 대상 명령의 오프셋임. 결과적으로 CACHE 명령의 존재는 전방 점프에는 투명하지만, 후방 점프를 추론할 때는 고려해야 함. 버전 3.13에서 변경: 출력이 점프 대상·예외 핸들러에 대해 명령 오프셋 대신 논리 레이블을 표시함. -O 명령줄 옵션과 show_offsets 인자가 추가됨. 버전 3.14에서 변경: -P 명령줄 옵션과 show_positions 인자가 추가됨. -S 명령줄 옵션도 추가됨.

출처: Python 표준 라이브러리

본문

함수 myfunc()가 주어지면:

def myfunc(alist):
    return len(alist)

다음 명령으로 myfunc()의 디스어셈블리를 표시할 수 있어요.

>>> dis.dis(myfunc)
  2           RESUME                   0

  3           LOAD_GLOBAL              1 (len + NULL)
              LOAD_FAST_BORROW         0 (alist)
              CALL                     1
              RETURN_VALUE

("2"는 줄 번호예요.)

명령줄 인터페이스

dis 모듈은 명령줄에서 스크립트로 호출할 수 있어요.

python -m dis [-h] [-C] [-O] [-P] [-S] [infile]

다음 옵션을 받아들여요.

  • -h, --help — 사용법을 표시하고 종료.
  • -C, --show-caches — 인라인 캐시를 표시해요. (버전 3.13에 추가됨.)
  • -O, --show-offsets — 명령의 오프셋을 표시해요. (버전 3.13에 추가됨.)
  • -P, --show-positions — 소스 코드에서 명령의 위치를 표시해요. (버전 3.14에 추가됨.)
  • -S, --specialized — 특화된 바이트코드를 표시해요. (버전 3.14에 추가됨.)

infile이 지정되면 그 디스어셈블된 코드가 stdout에 쓰여져요. 그렇지 않으면 stdin에서 받은 컴파일된 소스 코드에 대해 디스어셈블이 수행돼요.

바이트코드 분석

버전 3.4에 추가됨.

바이트코드 분석 API는 Python 코드 조각을 Bytecode 객체로 감싸 컴파일된 코드의 세부 사항에 쉽게 접근하게 해 줘요.

class dis.Bytecode(x, *, first_line=None, current_offset=None, show_caches=False, adaptive=False, show_offsets=False, show_positions=False)

함수, 제너레이터, 비동기 제너레이터, 코루틴, 메서드, 소스 코드 문자열, 또는 코드 객체(compile()이 돌려주는)에 해당하는 바이트코드를 분석해요.

이것은 아래 나열된 많은 함수, 특히 get_instructions()의 편의 래퍼예요. Bytecode 인스턴스를 반복하면 바이트코드 연산을 Instruction 인스턴스로 산출하니까요.

first_lineNone이 아니면 디스어셈블된 코드의 첫 소스 줄에 대해 보고해야 할 줄 번호를 나타내요. 그렇지 않으면 소스 줄 정보(있으면)를 디스어셈블된 코드 객체에서 직접 가져와요.

current_offsetNone이 아니면 디스어셈블된 코드의 명령 오프셋을 가리켜요. 이것을 설정하면 dis()가 지정된 opcode에 "현재 명령" 표시를 보여 줘요.

show_cachesTruedis()가 인터프리터가 바이트코드를 특화하는 데 사용하는 인라인 캐시 항목을 표시해요.

adaptiveTruedis()가 원래 바이트코드와 다를 수 있는 특화된 바이트코드를 표시해요.

show_offsetsTruedis()가 출력에 명령 오프셋을 포함해요.

show_positionsTruedis()가 출력에 명령 소스 코드 위치를 포함해요.

classmethod from_traceback(tb, *, show_caches=False)

주어진 트레이스백에서 Bytecode 인스턴스를 만들고, 예외를 일으킨 명령으로 current_offset을 설정해요.

codeobj

컴파일된 코드 객체.

first_line

코드 객체의 첫 소스 줄(사용 가능하면).

dis()

바이트코드 연산의 포맷된 뷰를 돌려줘요(dis.dis()가 출력하는 것과 같지만 멀티라인 문자열로 반환).

info()

코드 객체에 대한 상세 정보를 담은 포맷된 멀티라인 문자열을 돌려줘요. code_info()와 같아요.

버전 3.7에서 변경: 이제 코루틴과 비동기 제너레이터 객체를 처리할 수 있음. 버전 3.11에서 변경: show_cachesadaptive 매개변수 추가. 버전 3.13에서 변경: show_offsets 매개변수 추가. 버전 3.14에서 변경: show_positions 매개변수 추가.

예시:

>>> bytecode = dis.Bytecode(myfunc)
>>> for instr in bytecode:
...     print(instr.opname)
...
RESUME
LOAD_GLOBAL
LOAD_FAST_BORROW
CALL
RETURN_VALUE

분석 함수

dis 모듈은 입력을 원하는 출력으로 직접 변환하는 다음 분석 함수들도 정의해요. 단일 연산만 수행한다면 유용할 수 있어요. 중간 분석 객체가 필요 없으니까요.

dis.code_info(x)

제공된 함수, 제너레이터, 비동기 제너레이터, 코루틴, 메서드, 소스 코드 문자열 또는 코드 객체에 대한 상세 코드 객체 정보를 담은 포맷된 멀티라인 문자열을 돌려줘요.

코드 정보 문자열의 정확한 내용은 구현에 크게 의존하고, Python VM이나 릴리스 간에 임의로 바뀔 수 있다는 점에 주의하세요.

버전 3.2에 추가됨. 버전 3.7에서 변경: 이제 코루틴과 비동기 제너레이터 객체를 처리할 수 있음.

dis.show_code(x, *, file=None)

제공된 함수, 메서드, 소스 코드 문자열 또는 코드 객체에 대한 상세 코드 객체 정보를 file(file이 지정되지 않으면 sys.stdout)로 출력해요.

print(code_info(x), file=file)의 편리한 약식으로, 인터프리터 프롬프트에서 대화형 탐색을 위해 의도됐어요.

버전 3.2에 추가됨. 버전 3.4에서 변경: file 매개변수 추가.

dis.dis(x=None, *, file=None, depth=None, show_caches=False, adaptive=False, show_offsets=False, show_positions=False)

x 객체를 디스어셈블해요. x는 모듈, 클래스, 메서드, 함수, 제너레이터, 비동기 제너레이터, 코루틴, 코드 객체, 소스 코드 문자열 또는 원시 바이트코드의 바이트 시퀀스를 나타낼 수 있어요. 모듈이면 모든 함수를 디스어셈블하고, 클래스면 (클래스·정적 메서드를 포함한) 모든 메서드를 디스어셈블해요. 코드 객체나 원시 바이트코드 시퀀스면 바이트코드 명령마다 한 줄을 출력해요. 중첩된 코드 객체도 재귀적으로 디스어셈블해요. 여기엔 제너레이터 표현식, 중첩 함수, 중첩 클래스 본문, 어노테이션 스코프용 코드 객체가 포함될 수 있어요. 문자열은 디스어셈블되기 전에 먼저 compile() 내장 함수로 코드 객체에 컴파일돼요. 객체가 제공되지 않으면 이 함수는 마지막 트레이스백을 디스어셈블해요.

디스어셈블은 제공된 file 인자(제공되면)로, 아니면 sys.stdout으로 텍스트로 쓰여져요.

재귀의 최대 깊이는 depthNone이 아니면 depth로 제한돼요. depth=0은 재귀가 없다는 뜻이에요.

show_cachesTrue면 인터프리터가 바이트코드를 특화하는 데 사용하는 인라인 캐시 항목을 표시해요. adaptiveTrue면 원래 바이트코드와 다를 수 있는 특화된 바이트코드를 표시해요.

버전 3.4에서 변경: file 매개변수 추가. 버전 3.7에서 변경: 재귀 디스어셈블 구현과 depth 매개변수 추가. 코루틴·비동기 제너레이터 객체 처리 가능. 버전 3.11에서 변경: show_cachesadaptive 매개변수 추가. 버전 3.13에서 변경: show_offsets 매개변수 추가. 버전 3.14에서 변경: show_positions 매개변수 추가.

dis.distb(tb=None, *, file=None, show_caches=False, adaptive=False, show_offset=False, show_positions=False)

트레이스백의 스택 최상단 함수를 디스어셈블해요. 트레이스백이 전달되지 않으면 마지막 트레이스백을 사용해요. 예외를 일으킨 명령이 표시돼요.

dis.disassemble(code, lasti=-1, *, file=None, show_caches=False, adaptive=False, show_offsets=False, show_positions=False)

dis.disco(code, lasti=-1, *, file=None, show_caches=False, adaptive=False, show_offsets=False, show_positions=False)

코드 객체를 디스어셈블해요. lasti가 제공되면 마지막 명령을 표시해요. 출력은 다음 열로 나뉘어요.

  • 명령의 소스 코드 위치. show_positions가 참이면 완전한 위치 정보가 표시되고, 그렇지 않으면(기본값) 줄 번호만 표시돼요.
  • 현재 명령(-->로 표시).
  • 레이블된 명령(>>로 표시).
  • 명령의 주소.
  • 연산 코드 이름.
  • 연산 매개변수.
  • 괄호 안의 매개변수 해석.

매개변수 해석은 지역·전역 변수 이름, 상수 값, 분기 대상, 비교 연산자를 인식해요.

디스어셈블은 제공된 file 인자로, 아니면 sys.stdout으로 텍스트로 쓰여져요.

dis.get_instructions(x, *, first_line=None, show_caches=False, adaptive=False)

제공된 함수, 메서드, 소스 코드 문자열 또는 코드 객체의 명령에 대한 이터레이터를 돌려줘요.

이터레이터는 제공된 코드의 각 연산 세부 사항을 주는 일련의 Instruction 명명된 튜플을 생성해요.

first_lineNone이 아니면 디스어셈블된 코드의 첫 소스 줄에 대해 보고해야 할 줄 번호를 나타내요. 그렇지 않으면 소스 줄 정보(있으면)를 디스어셈블된 코드 객체에서 직접 가져와요.

adaptive 매개변수는 dis()에서처럼 작동해요.

버전 3.4에 추가됨. 버전 3.11에서 변경: show_cachesadaptive 매개변수 추가. 버전 3.13에서 변경: show_caches 매개변수가 폐기되고 효과가 없음. 이터레이터가 (show_caches 값과 무관하게) cache_info 필드가 채워진 Instruction 인스턴스를 생성하고, 캐시 항목에 대한 별도 항목을 더 이상 생성하지 않음.

dis.findlinestarts(code)

이 제너레이터 함수는 코드 객체 codeco_lines() 메서드를 사용해 소스 코드에서 줄이 시작되는 오프셋을 찾아요. (offset, lineno) 쌍으로 생성돼요.

버전 3.6에서 변경: 줄 번호가 감소할 수 있음. 이전에는 항상 증가했음. 버전 3.10에서 변경: 코드 객체의 co_firstlineno·co_lnotab 속성 대신 PEP 626 co_lines() 메서드가 사용됨. 버전 3.13에서 변경: 소스 줄에 매핑되지 않는 바이트코드의 줄 번호는 None일 수 있음.

dis.findlabels(code)

원시 컴파일 바이트코드 문자열 code에서 점프 대상인 모든 오프셋을 검출하고, 그 오프셋 리스트를 돌려줘요.

dis.stack_effect(opcode, oparg=None, *, jump=None)

인자 oparg를 가진 opcode의 스택 효과를 계산해요.

코드에 점프 대상이 있고 jumpTruestack_effect()가 점프의 스택 효과를 돌려줘요. jumpFalse면 점프하지 않는 스택 효과를 돌려줘요. jumpNone(기본값)이면 두 경우의 최대 스택 효과를 돌려줘요.

버전 3.4에 추가됨. 버전 3.8에서 변경: jump 매개변수 추가. 버전 3.13에서 변경: oparg가 생략되거나(None) oparg=0에 대한 스택 효과가 이제 반환됨. 이전에는 자기 인자를 쓰는 opcode에 대해 오류였음. opcode가 사용하지 않을 때 정수 oparg를 전달하는 것도 더 이상 오류가 아니며, 이 경우 oparg는 무시됨.

Python 바이트코드 명령

get_instructions() 함수와 Bytecode 클래스는 Instruction 인스턴스로 바이트코드 명령의 세부 사항을 제공해요.

class dis.Instruction

바이트코드 연산의 세부 사항.

  • opcode — 연산의 숫자 코드. 아래 나열된 opcode 값과 Opcode 컬렉션의 바이트코드 값에 해당.
  • opname — 연산의 사람이 읽을 수 있는 이름.
  • baseopcode — 연산이 특화된 경우 기본 연산의 숫자 코드. 아니면 opcode와 같음.
  • baseopname — 연산이 특화된 경우 기본 연산의 사람이 읽을 수 있는 이름. 아니면 opname과 같음.
  • arg — 연산의 숫자 인자(있으면), 아니면 None.
  • opargarg의 별칭.
  • argval — 해석된 arg 값(있으면), 아니면 None.
  • argrepr — 연산 인자의 사람이 읽을 수 있는 설명(있으면), 아니면 빈 문자열.
  • offset — 바이트코드 시퀀스에서 연산의 시작 인덱스.
  • start_offset — 바이트코드 시퀀스에서 연산의 시작 인덱스. 접두 EXTENDED_ARG 연산이 있으면 포함하고, 아니면 offset과 같음.
  • cache_offset — 연산을 따르는 캐시 항목의 시작 인덱스.
  • end_offset — 연산을 따르는 캐시 항목의 끝 인덱스.
  • starts_line — 이 opcode가 소스 줄을 시작하면 True, 아니면 False.
  • line_number — 이 opcode에 연관된 소스 줄 번호(있으면), 아니면 None.
  • is_jump_target — 다른 코드가 여기로 점프하면 True, 아니면 False.
  • jump_target — 점프 연산이면 점프 대상의 바이트코드 인덱스, 아니면 None.
  • positions — 이 명령이 덮는 시작·끝 위치를 담은 dis.Positions 객체.
  • cache_info — 이 명령의 캐시 항목에 대한 정보로, (name, size, data) 형식의 삼중항. namesize는 캐시 형식을, data는 캐시 내용을 설명. cache_info는 명령에 캐시가 없으면 None.

버전 3.4에 추가됨. 버전 3.11에서 변경: positions 필드 추가. 버전 3.13에서 변경: starts_line 필드 변경. start_offset, cache_offset, end_offset, baseopname, baseopcode, jump_target, oparg, line_number, cache_info 필드 추가.

class dis.Positions

정보를 사용할 수 없으면 일부 필드는 None일 수 있어요. lineno, end_lineno, col_offset, end_col_offset. (버전 3.11에 추가됨.)

바이트코드 명령 참조

Python 컴파일러는 현재 다음 바이트코드 명령들을 생성해요. 아래에서 인터프리터 스택을 STACK이라고 부르고, Python 리스트인 것처럼 연산을 설명할게요. 스택의 맨 위는 STACK[-1]에 해당해요.

일반 명령 (General instructions):

  • NOP — 아무것도 하지 않는 코드. 바이트코드 최적화기가 자리 표시자로, 그리고 줄 추적 이벤트 생성에 사용.
  • NOT_TAKEN — 아무것도 하지 않는 코드. 인터프리터가 sys.monitoringBRANCH_LEFT·BRANCH_RIGHT 이벤트를 기록하는 데 사용. (3.14)
  • POP_ITER — 스택 맨 위에서 이터레이터를 제거. (3.14)
  • POP_TOP — 스택 맨 위 항목을 제거: STACK.pop()
  • END_FOR — 스택 맨 위 항목을 제거. POP_TOP와 동일. 루프 끝에서 정리하는 데 사용. (3.12)
  • END_SENDdel STACK[-2] 구현. 제너레이터가 종료될 때 정리. (3.12)
  • COPY(i) — i번째 항목을 원래 위치에서 제거하지 않고 스택 맨 위로 푸시: assert i > 0; STACK.append(STACK[-i]) (3.11)
  • SWAP(i) — 스택 맨 위와 i번째 요소를 교환: STACK[-i], STACK[-1] = STACK[-1], STACK[-i] (3.11)
  • CACHE — 실제 명령이 아니라, 인터프리터가 유용한 데이터를 바이트코드 자체에 캐시하기 위한 여분 공간을 표시하는 opcode. 모든 dis 유틸리티에 자동으로 숨겨지지만 show_caches=True로 볼 수 있음. (3.11)

단항 연산 (Unary operations) — 스택 맨 위를 취해 연산을 적용하고 결과를 다시 푸시:

  • UNARY_NEGATIVESTACK[-1] = -STACK[-1]
  • UNARY_NOTSTACK[-1] = not STACK[-1] (3.13부터 정확한 bool 피연산자 요구)
  • UNARY_INVERTSTACK[-1] = ~STACK[-1]
  • GET_ITERSTACK[-1] = iter(STACK[-1])
  • GET_YIELD_FROM_ITERSTACK[-1]이 제너레이터 이터레이터·코루틴 객체면 그대로 두고, 아니면 iter(STACK[-1])로 변환. (3.5)
  • TO_BOOLSTACK[-1] = bool(STACK[-1]) (3.13)

이진·제자리 연산 (Binary and in-place operations) — 스택 맨 위 두 항목(STACK[-1], STACK[-2])을 제거하고 연산 후 결과를 다시 푸시. 제자리 연산은 STACK[-2]가 지원할 때 제자리로 수행되고 결과 STACK[-1]이 원래 STACK[-2]일 수 있음:

  • BINARY_OP(op) — 이진·제자리 연산자 구현: rhs = STACK.pop(); lhs = STACK.pop(); STACK.append(lhs op rhs) (3.11). (3.14) :NB_SUBSCR oparg로 이진 서브스크립트 구현(BINARY_SUBSCR 대체).
  • STORE_SUBSCRkey = STACK.pop(); container = STACK.pop(); value = STACK.pop(); container[key] = value
  • DELETE_SUBSCRkey = STACK.pop(); container = STACK.pop(); del container[key]
  • BINARY_SLICEend = STACK.pop(); start = STACK.pop(); container = STACK.pop(); STACK.append(container[start:end]) (3.12)
  • STORE_SLICEend/start/container/value = STACK.pop()...; container[start:end] = value (3.12)

코루틴 opcode (Coroutine opcodes):

  • GET_AWAITABLE(where)get_awaitable로 STACK[-1] 해석. where이 1이면 __aenter__ 호출 후, 2면 __aexit__ 호출 후를 나타냄. (3.5, 3.11에서 oparg)
  • GET_AITERSTACK[-1] = STACK[-1].__aiter__() (3.5)
  • GET_ANEXTSTACK.append(get_awaitable(STACK[-1].__anext__())) (3.5)
  • END_ASYNC_FOR — async for 루프 종료. 스택에 async iterable(STACK[-2])과 발생 예외(STACK[-1])를 담고, 둘 다 팝. StopAsyncIteration이 아니면 재발생. (3.8)
  • CLEANUP_THROW — 현재 프레임을 통한 throw()·close() 호출 중 발생한 예외 처리. STACK[-1]StopIteration이면 3개 값을 팝하고 value 멤버를 푸시, 아니면 재발생. (3.12)

기타 opcode (Miscellaneous opcodes):

  • SET_ADD(i)item = STACK.pop(); set.add(STACK[-i], item) — set 컴프리헨션.
  • LIST_APPEND(i)item = STACK.pop(); list.append(STACK[-i], item) — list 컴프리헨션.
  • MAP_ADD(i)value = STACK.pop(); key = STACK.pop(); dict.__setitem__(STACK[-i], key, value) — dict 컴프리헨션. (3.1)
  • RETURN_VALUESTACK[-1]을 함수 호출자에게 반환.
  • YIELD_VALUE — 제너레이터에서 STACK.pop()을 생성. (3.11~3.13에서 oparg 의미 변경)
  • SETUP_ANNOTATIONSlocals()__annotations__가 정의됐는지 확인, 없으면 빈 dict로 설정. (3.6)
  • POP_EXCEPT — 예외 상태 복원에 쓰는 스택 값 하나를 팝. (3.11)
  • RERAISE — 스택 맨 위의 현재 예외를 재발생. oparg가 0이 아니면 f_lasti 설정용 값을 추가로 팝. (3.9)
  • PUSH_EXC_INFO — 값 팝, 현재 예외를 맨 위에 푸시, 원래 팝 값 다시 푸시. (3.11)
  • CHECK_EXC_MATCHexcept용 예외 매칭. STACK[-2]STACK[-1]과 매칭되는 예외인지 테스트. (3.11)
  • CHECK_EG_MATCHexcept*용 예외 매칭. (3.11)
  • WITH_EXCEPT_STARTwith문에서 예외 발생 시 context_manager.__exit__(*exc_info()) 호출 구현. (3.9)
  • LOAD_COMMON_CONSTANT — 공통 상수를 스택에 푸시. assert 문이 AssertionError 로드에 사용. (3.14)
  • LOAD_BUILD_CLASSbuiltins.__build_class__()를 스택에 푸시, 클래스 구성에 호출.
  • GET_LENSTACK.append(len(STACK[-1])). match 문에서 사용. (3.10)
  • MATCH_MAPPINGSTACK[-1]이 Mapping이면 True, 아니면 False 푸시. (3.10)
  • MATCH_SEQUENCESTACK[-1]이 Sequence이면 True, 아니면 False 푸시. (3.10)
  • MATCH_KEYSSTACK[-1]은 매핑 키 튜플, STACK[-2]는 match 대상. (3.10)

이름·변수 접근 (Name/variable access):

  • STORE_NAME(namei)name = STACK.pop().
  • DELETE_NAME(namei)del name.
  • UNPACK_SEQUENCE(count)STACK[-1]count개의 개별 값으로 오른쪽→왼쪽으로 언팩.
  • UNPACK_EX(counts) — starred 대상이 있는 할당 구현. 리스트 값 앞·뒤 값 수는 255로 제한.
  • STORE_ATTR(namei)obj = STACK.pop(); value = STACK.pop(); obj.name = value
  • DELETE_ATTR(namei)obj = STACK.pop(); del obj.name
  • STORE_GLOBAL(namei) / DELETE_GLOBAL(namei) — 글로벌로 저장·삭제.
  • LOAD_CONST(consti)co_consts[consti]를 스택에 푸시.
  • LOAD_SMALL_INT(i) — 정수 i(range(256))를 스택에 푸시. (3.14)
  • LOAD_NAME(namei)co_names[namei]의 값을 locals→globals→builtins 순으로 조회해 푸시.
  • LOAD_LOCALS — locals 딕셔너리 참조를 푸시. (3.12)
  • LOAD_FROM_DICT_OR_GLOBALS(i) — 매핑을 팝해 co_names[namei] 조회, 없으면 globals·builtins에서. (3.12)

컨테이너·컬렉션 구성:

  • BUILD_TEMPLATE — 문자열 튜플과 보간 튜플로 새 Template 인스턴스 구성. (3.14)
  • BUILD_INTERPOLATION(format) — 값과 그 소스 표현식으로 새 Interpolation 인스턴스 구성. (3.14)
  • BUILD_TUPLE(count) — count개 항목 소비로 튜플 생성.
  • BUILD_LIST(count) / BUILD_SET(count) — 튜플과 같지만 리스트·셋 생성.
  • BUILD_MAP(count) — 새 dict 객체 푸시.
  • BUILD_STRING(count) — count개 문자열 연결. (3.6)
  • LIST_EXTEND(i)seq = STACK.pop(); list.extend(STACK[-i], seq) (3.9)
  • SET_UPDATE(i)seq = STACK.pop(); set.update(STACK[-i], seq) (3.9)
  • DICT_UPDATE(i)map = STACK.pop(); dict.update(STACK[-i], map) (3.9)
  • DICT_MERGE(i)DICT_UPDATE와 같지만 중복 키면 예외. (3.9)

속성·호출:

  • LOAD_ATTR(namei)namei의 낮은 비트가 0이면 getattr(STACK[-1], co_names[namei>>1])로 대체. 1이면 메서드 로드 시도. (3.12)
  • LOAD_SUPER_ATTR(namei)super()의 0-인자·2-인자 형태 모두 구현. (3.12)
  • COMPARE_OP(opname) — 불리언 연산 수행. (3.13)
  • IS_OP(invert)is, invert가 1이면 is not. (3.9)
  • CONTAINS_OP(invert)in, invert가 1이면 not in. (3.9)
  • IMPORT_NAME(namei) — 모듈 import.
  • IMPORT_FROM(namei) — 스택 맨 위 모듈에서 속성 로드.

점프·흐름 제어:

  • JUMP_FORWARD(delta) — 바이트코드 카운터를 delta만큼 증가.
  • JUMP_BACKWARD(delta) — 바이트코드 카운터를 delta만큼 감소. 인터럽트 검사. (3.11)
  • JUMP_BACKWARD_NO_INTERRUPT(delta) — 감소만, 인터럽트 검사 안 함. (3.11)
  • POP_JUMP_IF_TRUE(delta) / POP_JUMP_IF_FALSE(delta) — 스택 맨 위가 참/거짓이면 카운터 증가, 팝. (3.13부터 정확한 bool 피연산자 요구)
  • POP_JUMP_IF_NOT_NONE(delta) / POP_JUMP_IF_NONE(delta)None 여부로 점프. (3.11)
  • FOR_ITER(delta)STACK[-1]은 이터레이터, __next__() 호출. (3.12)
  • LOAD_GLOBAL(namei) — 글로벌 로드. (3.11)
  • LOAD_FAST(var_num) — 지역 co_varnames[var_num] 참조 푸시. (3.12)
  • LOAD_FAST_BORROW(var_num) — 빌려온 참조 푸시. (3.14)
  • LOAD_FAST_LOAD_FAST(var_nums) — 두 지역 참조 푸시. (3.13)
  • LOAD_FAST_BORROW_LOAD_FAST_BORROW(var_nums) — 두 빌려온 참조 푸시. (3.14)
  • LOAD_FAST_CHECK(var_num) — 초기화 안 됐으면 UnboundLocalError. (3.12)
  • LOAD_FAST_AND_CLEAR(var_num) — 참조 푸시 후 NULL로 설정. (3.12)
  • STORE_FAST(var_num)STACK.pop()을 지역에 저장.
  • STORE_FAST_STORE_FAST(var_nums) / STORE_FAST_LOAD_FAST(var_nums)(3.13)
  • DELETE_FAST(var_num) — 지역 삭제.
  • MAKE_CELL(i) — 슬롯 i에 새 cell 생성. (3.11)
  • LOAD_DEREF(i) — "fast locals" 저장소의 cell을 로드. (3.11)
  • LOAD_FROM_DICT_OR_DEREF(i) — 클래스 본문의 클로저 변수 로드. (3.12)
  • STORE_DEREF(i) — cell에 저장. (3.11)
  • DELETE_DEREF(i) — cell 비우기. (3.2)
  • COPY_FREE_VARS(n) — 클로저의 n개 자유 변수를 프레임으로 복사. (3.11)
  • RAISE_VARARGS(argc)raise 문의 3가지 형태. 0: 재발생, 1: STACK[-1] 발생, 2: STACK[-2] from STACK[-1].
  • CALL(argc) — callable 호출. (3.11, 3.13)
  • CALL_KW(argc) — 키워드 인자 포함 호출. (3.13)
  • CALL_FUNCTION_EX(flags) — 가변 위치·키워드 인자로 호출. (3.6)
  • PUSH_NULL — NULL 푸시. (3.11)
  • MAKE_FUNCTIONSTACK[-1]의 코드 객체로 새 함수 객체 푸시. (3.10, 3.11, 3.13)
  • SET_FUNCTION_ATTRIBUTE(flag) — 함수 객체에 속성 설정. (3.13, 3.14)
  • BUILD_SLICE(argc) — 슬라이스 객체 푸시(argc는 2 또는 3).
  • EXTENDED_ARG(ext) — 기본 1바이트에 너무 큰 인자용 접두 opcode. opcode당 최대 3개의 접두 EXTENDED_ARG.
  • CONVERT_VALUE(oparg) — 값 문자열 변환(oparg 1=str, 2=repr, 3=ascii). f-string 구현. (3.13)
  • FORMAT_SIMPLE — 스택 맨 위 값 포맷(value.__format__("")). (3.13)
  • FORMAT_WITH_SPEC — 주어진 형식 지정으로 값 포맷. (3.13)
  • MATCH_CLASS(count) — 클래스 패턴 매칭. (3.10, 3.11)
  • RESUME(context) — no-op. 내부 추적·디버깅·최적화 검사. (3.11, 3.13)
  • RETURN_GENERATOR — 현재 프레임에서 제너레이터·코루틴·async 제너레이터 생성. (3.11)
  • SEND(delta)STACK[-1] = STACK[-2].send(STACK[-1]). yield from·await에 사용. (3.11)
  • HAVE_ARGUMENT — 실제 opcode가 아님. 인자를 쓰지 않는 opcode와 쓰는 opcode의 경계선. (폐기, hasarg 사용)
  • CALL_INTRINSIC_1 — 한 인자로 내장 함수 호출. (3.12)
  • CALL_INTRINSIC_2 — 두 인자로 내장 함수 호출. (3.12)
  • LOAD_SPECIALSTACK[-1]에 대해 특수 메서드 조회 수행. (3.14)

의사 명령 (Pseudo-instructions) — 실제 Python 바이트코드에는 나타나지 않아요. 컴파일러가 사용하지만 바이트코드 생성 전에 실제 opcode로 대체되거나 제거돼요.

  • SETUP_FINALLY(target) — 다음 코드 블록용 예외 핸들러 설정.
  • SETUP_CLEANUP(target)SETUP_FINALLY와 같지만, 예외 시 RERAISE가 복원할 수 있게 마지막 명령(lasti)도 푸시.
  • SETUP_WITH(target)SETUP_CLEANUP과 같지만 컨텍스트 관리자의 __enter__()/__aenter__() 반환 값 푸시. with·async with에 사용.
  • POP_BLOCK — 마지막 SETUP_FINALLY/SETUP_CLEANUP/SETUP_WITH와 연관된 코드 블록의 끝 표시.
  • LOAD_CONST_IMMORTAL(consti)LOAD_CONST와 같지만 불멸 객체에 더 효율적.
  • JUMP, JUMP_NO_INTERRUPT — 무방향 상대 점프. 어셈블러가 방향(전방/후방) 버전으로 대체.
  • JUMP_IF_TRUE, JUMP_IF_FALSE — 스택에 영향을 주지 않는 조건 점프.
  • LOAD_CLOSURE(i) — "fast locals" 저장소 슬롯 i의 cell 참조 푸시. (3.13부터 의사 명령)

Opcode 컬렉션

바이트코드 명령의 자동 인트로스펙션을 위한 컬렉션들:

  • dis.opname — 연산 이름의 시퀀스. 바이트코드로 인덱싱 가능.
  • dis.opmap — 연산 이름을 바이트코드로 매핑하는 딕셔너리.
  • dis.cmp_op — 모든 비교 연산 이름의 시퀀스.
  • dis.hasarg — 인자를 사용하는 바이트코드의 시퀀스. (3.12)
  • dis.hasconst — 상수에 접근하는 바이트코드의 시퀀스.
  • dis.hasfree — 자유(클로저) 변수에 접근하는 바이트코드의 시퀀스. 여기서 'free'는 내부 스코프가 참조하는 현재 스코프의 이름이나, 이 스코프가 참조하는 외부 스코프의 이름을 의미. global·builtin 스코프 참조는 포함하지 않음.
  • dis.hasname — 이름으로 속성에 접근하는 바이트코드의 시퀀스.
  • dis.hasjump — 점프 대상을 가지는 바이트코드의 시퀀스. 모든 점프는 상대적. (3.13)
  • dis.haslocal — 지역 변수에 접근하는 바이트코드의 시퀀스.
  • dis.hascompare — 불리언 연산의 바이트코드 시퀀스.
  • dis.hasexc — 예외 핸들러를 설정하는 바이트코드의 시퀀스. (3.12)
  • dis.hasjrel — 상대 점프 대상을 가지는 바이트코드의 시퀀스. (3.13부터 폐기, hasjump 사용 — 모든 점프가 이제 상대적.)
  • dis.hasjabs — 절대 점프 대상을 가지는 바이트코드의 시퀀스. (3.13부터 폐기, 이 리스트는 비어 있음.)

버전 3.12에서 변경: 컬렉션에 이제 의사 명령과 계측 명령(MIN_PSEUDO_OPCODEMIN_INSTRUMENTED_OPCODE 이상의 값을 가진 opcode)도 포함됨.