728x90
반응형

이 글은 간단한 Python 코드에 대한 bytecode가 어떻게 되어있는지를 살펴본다.
다음의 글을 미리 읽어보길 권함:
2025.03.11 - [Python] - [Py] dis 모듈 - Python
[Py] dis 모듈 - Python
Python의 dis 모듈: 바이트코드 disassemble하기Python은 인터프리터 언어지만, 실행 전에 source code (원시코드)를 bytecode (바이트코드) 라는 중간 형태로 컴파일하여 성능을 향상시킴.이 바이트코드는 Pyt
ds31x.tistory.com
(main) script 부분
Python에서 "main script"는
프로그램 실행을 시작하는 주 진입점이 되는 Python 파일 또는 source code를 의미함.
0 0 RESUME 0
1 2 LOAD_CONST 0 (<code object func at 0x103661890,
file "./test.py", line 1>)
4 MAKE_FUNCTION 0
6 STORE_NAME 0 (func)
RESUME 0: 코드 실행 시작LOAD_CONST 0: 상수 테이블의 인덱스 0에서 func 함수의 코드 객체를 읽어와 스택에 Push- 이 코드 객체는 컴파일 단계에서 생성되어 상수 테이블에 저장되었음
MAKE_FUNCTION 0: 스택에서 코드 객체를 Pop하여 호출 가능한 함수 객체 생성 후 스택에 PushSTORE_NAME 0 (func): 스택에서 함수 객체를 팝하여 전역 네임스페이스 딕셔너리의 'func' 키에 저장
6 8 LOAD_CONST 1 (10)
10 STORE_NAME 1 (a)
7 12 LOAD_CONST 2 (999999)
14 STORE_NAME 2 (b)
LOAD_CONST 1 (10): 상수 테이블의 인덱스 1에서 값 10을 읽어와 스택에 PushSTORE_NAME 1 (a): 스택에서 값을 Pop하여 전역 네임스페이스의 'a' 키에 저장LOAD_CONST 2 (999999): 상수 테이블의 인덱스 2에서 값 999999를 읽어와 스택에 PushSTORE_NAME 2 (b): 스택에서 값을 Pop하여 전역 네임스페이스의 'b' 키에 저장
8 16 PUSH_NULL
18 LOAD_NAME 0 (func)
20 LOAD_NAME 1 (a)
22 LOAD_NAME 2 (b)
24 CALL 2
32 STORE_NAME 3 (c)
PUSH_NULL: 예외 처리용 null을 스택에 PushLOAD_NAME 0 (func): 전역 네임스페이스에서 'func' 키의 값(함수 객체)을 읽어와 스택에 PushLOAD_NAME 1 (a): 전역 네임스페이스에서 'a' 키의 값(10)을 읽어와 스택에 PushLOAD_NAME 2 (b): 전역 네임스페이스에서 'b' 키의 값(999999)을 읽어와 스택에 PushCALL 2: 스택에서 함수와 2개의 인자를 Pop하여 함수 호출, 함수 실행 후 결과를 스택에 PushSTORE_NAME 3 (c): 스택에서 함수 호출 결과를 Pop하여 전역 네임스페이스의 'c' 키에 저장
10 34 PUSH_NULL
36 LOAD_NAME 4 (print)
38 LOAD_NAME 3 (c)
40 CALL 1
48 POP_TOP
50 RETURN_CONST 3 (None)
PUSH_NULL: 예외 처리용 null을 스택에 PushLOAD_NAME 4 (print): 내장(builtins) 네임스페이스에서 'print' 키의 값(내장 함수)을 읽어와 스택에 PushLOAD_NAME 3 (c): 전역 네임스페이스에서 'c' 키의 값을 읽어와 스택에 PushCALL 1: 스택에서 'print' 함수와 1개의 인자를 Pop하여 함수 호출, 결과(None)를 스택에 PushPOP_TOP: 스택 맨 위의 값(None)을 Pop하여 버림RETURN_CONST 3 (None): 상수 테이블의 인덱스 3에서None을 읽어와 반환하고 프로그램 종료
func 함수 부분
1 0 RESUME 0
2 2 LOAD_FAST 0 (a)
4 LOAD_FAST 1 (b)
6 BINARY_OP 0 (+)
10 STORE_FAST 2 (c)
3 12 LOAD_FAST 2 (c)
14 RETURN_VALUE
RESUME 0: 함수 실행 시작LOAD_FAST 0 (a): 지역 변수 배열의 인덱스 0에서 매개변수 'a'의 값을 읽어와 스택에 Push- 함수 호출 시 전달된 인자가 이 배열에 저장됨
LOAD_FAST 1 (b): 지역 변수 배열의 인덱스 1에서 매개변수 'b'의 값을 읽어와 스택에 PushBINARY_OP 0 (+): 스택에서 두 값을 Pop하여 더한 후 결과를 스택에 Push- 0은 덧셈 연산을 나타내는 오퍼랜드
STORE_FAST 2 (c): 스택에서 결과 값을 Pop하여 지역 변수 배열의 인덱스 2('c')에 저장LOAD_FAST 2 (c): 지역 변수 배열의 인덱스 2에서 'c'의 값을 읽어와 스택에 PushRETURN_VALUE: 스택에서 값을 팝하여 함수의 반환 값으로 사용, 호출자의 스택에 Push됨
데이터 저장소 요약
- 상수 테이블(co_consts):
- 컴파일 시점에 결정되는 모든 상수 값(숫자, 문자열, 코드 객체 등)을 저장
LOAD_CONST명령어가 여기서 값을 읽어옴
- 전역 네임스페이스:
- 모듈 수준의 변수들을 저장하는 딕셔너리
STORE_NAME이 여기에 값을 저장하고,LOAD_NAME이 여기서 값을 읽어옴
- 지역 변수 배열:
- 함수 내의 지역 변수와 매개변수를 저장하는 배열
STORE_FAST가 여기에 값을 저장하고,LOAD_FAST가 여기서 값을 읽어옴- 인덱스 기반 접근으로 딕셔너리 조회보다 빠름
- 내장 네임스페이스:
- print(), len() 등의 내장 함수를 저장
LOAD_NAME이 전역 네임스페이스에서 찾지 못한 이름을 여기서 검색
dis 모듈 사용법
위의 bytescode 결과에 대응하는 Python 코드 소스 파일 test.py는 다음과 같음
# test.py
def func(a,b):
c = a+b
return c
a = 10
b = 999999
c = func(a,b)
print(c)
위의 결과를 얻어내는 커맨드는 다음임:
❯ python -m dis test.py
또는 소스코드를 사용하는 compile을 이용하는 방식도 있음
#dis_test.py
import dis
with open('./test.py', 'r') as f:
source = f.read()
# compile() 함수는
# 문자열 형태의 Python 소스 코드를 바이트코드로 변환하여
# code object를 생성하는 내장 함수
# 여러 statements를 다룰 때엔 "exec"를 통해 exec()함수 사용
code_obj = compile(source, "./test.py", "exec")
dis.dis(code_obj)
아니면 __pycache__ 의 .pyc 바이트코드 파일을 직접 사용하는 방법도 있음 (가장 버전을 타기 때문에 비추천)
import dis
import marshal
import importlib.util
import sys
# .pyc 파일 경로
pyc_path = "__pycache__/my_module.cpython-310.pyc" # 실제 파일 경로로 변경
# .pyc 파일의 헤더 크기 (Python 버전에 따라 다름)
# Python 3.7+ 에서는 일반적으로 16바이트
# Magic number (4bytes) + Bit field (4bytes) + Timestamp (4bytes) + Size (4bytes)
HEADER_SIZE = 16
# .pyc 파일 읽기
with open(pyc_path, 'rb') as f:
# 헤더 건너뛰기
f.seek(HEADER_SIZE)
# 바이트코드 로드
code_object = marshal.load(f)
# 바이트코드 디스어셈블
dis.dis(code_object)
marshal에 대해선 다음 URL을 참고:
2024.11.27 - [Python] - [Py] Serialization of Python: pickle
[Py] Serialization of Python: pickle
1. Python의 pickle 모듈Python의 pickle 모듈은 Python 객체를 직렬화(serialize)하여 파일 또는 메모리에 저장.저장된 데이터를 다시 역직렬화(deserialize)하여 원래 객체로 복원.데이터를 영구 저장하거나 네
ds31x.tistory.com
728x90
'CE' 카테고리의 다른 글
| [Programming] MVC, MVVM, and Qt's MV (0) | 2025.04.14 |
|---|---|
| [C] LLP64 vs. LP64 (0) | 2025.03.21 |
| Text File and Binary File: Hex Code (0) | 2025.03.11 |
| Apple II (1977년, Apple ][ ) (0) | 2025.03.11 |
| Switch로 컴퓨터(or 디지털논리회로) 만들기 - Claude Shannon (1937) (0) | 2025.03.11 |