왜 이 글이 다시 회자될까요?
500 Lines or Less라는 오픈소스 책의 한 챕터, "A Python Interpreter Written in Python"이 다시 개발자들 사이에서 돌고 있어요. 이 글은 Allison Kaptur가 쓴 건데, 파이썬으로 파이썬 인터프리터(Byterun)를 직접 구현해보면서 CPython이 내부적으로 어떻게 돌아가는지를 풀어낸 교육용 프로젝트입니다. 꽤 오래된 글이지만 최근 CPython의 JIT 논의나 PEP 744 같은 이야기들이 나오면서 "일단 바이트코드 인터프리터가 뭔지부터 제대로 이해하고 싶다"는 사람들이 다시 이 글을 찾고 있어요.
배경 설명을 잠깐 드리면, 우리가 python script.py를 실행하면 사실 파이썬은 그 코드를 바로 실행하는 게 아니에요. 먼저 바이트코드라는 중간 표현으로 컴파일하고, 그 바이트코드를 가상 머신(VM)이 한 줄씩 해석하면서 실제 연산을 수행합니다. 이 VM이 바로 인터프리터의 심장이에요. Byterun은 이 심장 부분만 따로 떼어내서 500줄짜리 파이썬 코드로 재구현한 거예요.
바이트코드와 VM, 쉽게 풀어보면
바이트코드가 뭐냐면, 사람이 쓴 파이썬 코드와 기계가 실행하는 기계어 사이에 있는 중간 언어라고 보면 돼요. 예를 들어 a + b라는 간단한 식은 CPython에서 대략 이런 바이트코드로 컴파일됩니다. LOAD_NAME a, LOAD_NAME b, BINARY_ADD. 단어 세 개짜리 명령 집합이죠. 첫 번째는 "a라는 변수 가져와서 스택에 올려", 두 번째는 "b도 올려", 세 번째는 "스택 위 두 개를 꺼내서 더하고 결과를 다시 올려"라는 뜻이에요.
핵심은 스택 머신이라는 구조예요. 레지스터 대신 임시 값들을 쌓아두는 스택이 있고, 모든 연산이 "스택에서 꺼내서 계산하고 스택에 다시 넣는" 방식으로 진행됩니다. 손으로 계산할 때 포스트잇에 숫자 써서 쌓아두고 위에서부터 집어 쓰는 느낌이에요. 이게 구현이 단순해서 교육용으로도 좋고, 실제로 JVM이나 .NET CLR도 비슷한 방식을 씁니다.
Byterun의 핵심은 거대한 while 루프와 if-elif 사슬이에요. 바이트코드를 한 개씩 읽어서 "이 명령이 LOAD_NAME이면 이걸 해라, BINARY_ADD면 저걸 해라" 하는 식의 거대한 dispatch 함수가 있고, 실행 상태는 Frame 객체에 담아둡니다. Frame이 뭐냐면, 하나의 함수 호출에 해당하는 실행 컨텍스트예요. 현재 어느 바이트코드를 실행 중인지, 로컬 변수는 뭐가 있는지, 스택 상태는 어떤지가 다 Frame 안에 들어있죠. 함수를 호출하면 새 Frame이 생기고, 리턴하면 Frame이 사라지는 구조입니다.
글에서 배울 수 있는 것들
Allison은 이 글에서 예외 처리와 제너레이터 같은 복잡한 제어 흐름까지 다뤄요. 특히 파이썬의 제너레이터가 어떻게 "중간에 멈췄다가 나중에 이어서 실행"되는지 궁금해했던 분들한테는 이 부분이 금광이에요. Byterun은 제너레이터를 구현할 때 Frame 자체를 일시정지 가능한 객체로 만들어서, yield를 만나면 Frame의 실행 포인터를 저장해두고 다음 next() 호출에 이어서 재개합니다. 코루틴이나 async/await의 내부 동작을 이해하는 첫걸음이 되는 개념이에요.
예외 처리도 재밌는데, 바이트코드 레벨에서 SETUP_EXCEPT라는 명령이 예외 핸들러 블록 정보를 블록 스택에 쌓아두고, 예외가 발생하면 이 블록 스택을 거슬러 올라가면서 적절한 핸들러를 찾는 방식이에요. 우리가 try/except로 쓰는 문법이 내부적으로는 이렇게 스택을 조작하는 몇 개의 바이트코드 명령으로 번역된다는 걸 보면 "아, 이래서 finally가 무조건 실행되는구나" 같은 감이 와요.
업계 맥락과 최근 흐름
이 글이 재조명되는 건 최근 파이썬 생태계의 변화와도 관련이 있어요. CPython 3.13부터 실험적 JIT이 들어갔고, PEP 703으로 GIL을 제거하는 no-GIL 파이썬 작업도 진행 중입니다. 이런 큰 변화를 따라가려면 결국 "바이트코드 인터프리터가 어떻게 동작하는가"를 이해해야 하는데, CPython 소스는 C로 짜여있고 매크로와 최적화 트릭이 많아서 읽기가 쉽지 않아요. Byterun처럼 파이썬으로 깔끔하게 재구현된 코드가 있으면 개념을 먼저 잡고 C 코드를 보러 갈 수 있어서 학습 곡선이 훨씬 완만해집니다.
유사한 프로젝트로는 PyPy가 있는데, PyPy는 교육용이 아니라 실제로 프로덕션에서 쓰이는 빠른 파이썬 구현체예요. RPython이라는 파이썬 서브셋으로 작성되고 JIT 컴파일러까지 붙어있죠. 또 MicroPython은 마이크로컨트롤러용으로 C로 재구현한 파이썬인데, 코드베이스가 CPython보다 작아서 VM 구조를 공부하기에 좋은 대안입니다.
한국 개발자에게 주는 시사점
한국에서 파이썬을 쓰는 개발자는 많지만, 인터프리터 내부까지 들여다보는 경험을 하는 분은 드물어요. 근데 이 차이가 실무에서 의외로 크게 드러납니다. 예를 들어 성능 튜닝을 할 때 "왜 리스트 컴프리헨션이 for 루프보다 빠른가", "왜 지역 변수가 전역 변수보다 빠른가" 같은 질문은 바이트코드를 dis 모듈로 뜯어보면 바로 답이 나오거든요. LOAD_FAST와 LOAD_GLOBAL의 비용 차이를 눈으로 보면 단순한 코딩 규칙이 아니라 구조적인 이유로 이해하게 돼요.
또 최근 한국에서도 Python 3.13의 GIL-free 빌드나 JIT에 대한 관심이 높아지고 있어서, 컨퍼런스 발표나 기술 블로그 글을 따라가려면 VM에 대한 기본기가 필수가 되고 있어요. Byterun 소스를 주말에 한 번 따라 읽어보는 것만으로도 그런 고급 주제를 훨씬 편하게 소화할 수 있게 됩니다.
마무리
결국 이 글의 가치는 "평소 당연하게 쓰던 파이썬이 내부적으로 얼마나 정교한 상태 머신인지를 500줄로 체감하게 해준다"는 거예요. 언어를 만든다는 게 멀리 있는 일이 아니라는 걸 알려주는 좋은 입문서죠.
여러분은 dis 모듈로 파이썬 바이트코드를 뜯어본 적 있으신가요? 평소 성능 이슈를 디버깅할 때 어느 레이어까지 파고 들어가세요? VM 레벨까지 내려가본 경험담이 있다면 나눠주세요.
🔗 출처: Hacker News
"비전공 직장인인데 반년 만에 수익 파이프라인을 여러 개 만들었습니다"
실제 수강생 후기- 비전공자도 6개월이면 첫 수익
- 20년 경력 개발자 직강
- 자동화 프로그램 + 소스코드 제공