파이썬 동작 원리, 바이트코드와 인터프리터를 쉽게 이해하기

파이썬 동작 원리, 바이트코드와 인터프리터를 쉽게 이해하기

0

내가 쓴 파이썬 코드 한 줄이 어떻게 컴퓨터를 움직일까. 사실 이걸 몰라도 코딩은 할 수 있다. 그래도 파이썬 동작 원리를 알아두면 에러를 만났을 때 당황이 줄고, 코드가 왜 그렇게 도는지 감이 잡힌다. 어렵지 않으니 한 번 훑어보자.

사람이 읽는 코드 문서가 중간 변환 단계를 거쳐 CPU 칩으로 흐르는 파이프라인, 파이썬 동작 원리를 담은 이미지
사람이 읽는 코드 문서가 중간 변환 단계를 거쳐 CPU 칩으로 흐른다. 이게 바로 대부분 프로그래밍 언어의 동작 원리다.

컴퓨터는 사람 말을 모른다

한국어나 영어처럼 우리가 쓰는 말을 자연어라 한다. 보통의 컴퓨터는 이 자연어를 알아듣지 못한다. 그래서 컴퓨터에 일을 시키려면 파이썬 같은 프로그래밍 언어가 필요하다. 그런데 사실 컴퓨터의 진짜 모국어는 0과 1로 된 기계어뿐이다. 우리가 파이썬으로 쓴 코드도, 결국 이 기계어로 번역돼야 CPU가 실행한다. 그 번역을 누가, 어떻게 하느냐가 동작 원리의 핵심이다.

파이썬 코드 자체는 사람이 읽기 좋게 생겼다. print("안녕") 같은 한 줄은 우리 눈엔 직관적이지만, CPU에는 외계어나 다름없다. 그 사이의 거리를 메우는 다리가 필요하고, 파이썬은 그 다리를 안에서 알아서 놓아준다. 우리가 다리 설계를 신경 쓰지 않아도 되는 것, 그게 파이썬이 편한 이유이자 동시에 안에서 무슨 일이 벌어지는지 한 번쯤 들여다볼 가치가 있는 이유다.

코드가 실행되는 흐름

파이썬 코드는 한 번에 기계어로 가지 않는다. 중간 단계를 하나 거친다. 흐름을 그리면 이렇다.

소스 코드(.py) → 파이썬 컴파일러 → 바이트코드(.pyc) → 파이썬 가상 머신(인터프리터) → 기계어 → CPU.

먼저 파이썬은 내가 쓴 소스 코드를 ‘바이트코드’라는 중간 코드로 컴파일한다. 이 바이트코드는 사람도, CPU도 아닌 그 중간 어디쯤의 명령어 모음이다. 그다음 파이썬 가상 머신(Python Virtual Machine, PVM)이 이 바이트코드를 한 줄씩 읽어 기계어로 바꿔 CPU에 넘긴다. 우리가 흔히 쓰는 표준 파이썬은 C 언어로 만들어진 ‘CPython’이라는 구현인데, python 파일.py를 칠 때마다 바로 이 CPython이 위 과정을 돌린다. GeeksforGeeks가 정리한 파이썬 내부 동작을 보면 이 흐름이 더 자세히 그려져 있다.

여기서 ‘컴파일’과 ‘인터프리터’라는 말이 헷갈릴 수 있다. 흔히 C나 자바는 컴파일 언어, 파이썬은 인터프리터 언어로 나누지만, 실제로 파이썬은 둘을 섞어 쓴다. 안에서 한 번 컴파일을 하고, 그 결과를 인터프리터가 실행하는 식이다. 그래서 ‘파이썬은 컴파일 안 한다’는 말은 정확히는 틀린 셈이다. 다만 그 컴파일이 자동으로, 보이지 않게 일어나기 때문에 우리가 신경 쓸 일이 없을 뿐이다.

두 번 변환하는 게 비효율 아닐까?

여기서 의문이 들 만하다. 컴파일도 하고 인터프리터도 거치니, 변환을 두 번 하는 셈이다. “그거 비효율 아니야?” 결론부터 말하면 정반대다. 이 중간 단계가 오히려 효율을 높인다. 이유는 두 가지다.

첫째, 바이트코드라는 중간 코드가 있어야 최소한의 최적화가 가능하다. 사람 말을 곧장 기계어로 직역하는 것보다, 한 번 정돈된 중간 형태를 거치는 편이 더 매끄럽다. 게다가 이 바이트코드는 운영체제에 상관없이 도는 크로스플랫폼 명령어라, 한 번 만들면 여러 환경에서 같은 방식으로 쓰인다.

둘째, 캐싱 덕분이다. 파이썬은 만든 바이트코드를 __pycache__ 폴더 안에 .pyc 파일로 저장해둔다. 다음에 같은 코드를 실행할 때, 소스가 바뀌지 않았다면 다시 컴파일하지 않고 저장해둔 .pyc를 바로 쓴다. 불필요한 번역을 건너뛰니 실행이 빨라진다. 두 번 변환하는 게 손해가 아니라, 두 번째부터 시간을 버는 구조인 셈이다.

비유하자면 이렇다. 외국어 문서를 매번 처음부터 통째로 번역하는 대신, 한 번 번역해 둔 사본을 책상 서랍에 넣어두는 것과 같다. 원문이 그대로면 서랍의 사본을 꺼내 쓰면 되고, 원문을 고쳤을 때만 다시 번역한다. 바이트코드라는 ‘중간 번역본’을 두는 이 방식이 바로 파이썬이 빠르면서도 유연할 수 있는 비결이다.

그래서 ‘인터프리터 언어’라고 부른다

이렇게 안에서는 컴파일을 거치지만, 우리 입장에선 파이썬이 그냥 ‘바로 실행되는 언어’처럼 느껴진다. 따로 컴파일·링크 버튼을 누를 필요가 없고, 에러가 나면 내가 쓴 .py 파일의 몇 번째 줄이 문제인지 바로 알려준다. 고치고 다시 돌리는 순환이 빠르다. 그래서 파이썬을 흔히 인터프리터 언어라 부른다. 입문자에게 친절한 이유가 여기에도 있다. 파이썬이 왜 첫 언어로 좋은지는 파이썬의 매력에서, 무엇을 만들 수 있는지는 파이썬으로 할 수 있는 것에서 더 다뤘다.

파이썬 동작 원리를 알면 무엇이 좋을까

솔직히 이 원리를 몰라도 코딩은 된다. 그래도 알아두면 분명히 도움이 된다. 예를 들어 프로젝트 폴더에 __pycache__라는 폴더가 생겨도 당황하지 않는다. 그게 파이썬이 만들어둔 캐시라는 걸 아니까. 에러 메시지가 어느 단계에서 나는지 감이 잡히고, “파이썬은 느리다”는 말이 어떤 맥락인지도 이해된다. AI가 짜 준 코드를 읽을 때도, 그 코드가 실제로 어떻게 도는지 떠올릴 수 있으면 검증이 한결 수월해진다. 코딩이 처음이라면 프로그래밍 배우기, 망설이는 그대에게부터 시작해도 좋다.

“파이썬은 느리다”는 말도 이 구조에서 나온다. 바이트코드를 가상 머신이 한 줄씩 해석하다 보니, 처음부터 기계어로 직접 컴파일되는 C 같은 언어보다 같은 작업을 느리게 처리할 때가 있다. 하지만 대부분의 일상적인 작업에서는 그 차이가 체감되지 않고, 정작 속도가 중요한 부분은 C로 짜인 라이브러리가 대신 처리한다. 데이터 분석이나 AI에서 파이썬이 빠르게 느껴지는 건 바로 이 덕분이다. 그러니 ‘느리다’는 한 문장만 보고 겁먹을 필요는 없다.

원리는 거들 뿐, 일단 만들어보자

파이썬 동작 원리를 한 번 이해해두면 코드를 보는 눈이 한 뼘 깊어진다. 다만 이걸 완벽히 외운 다음에야 코딩을 시작할 필요는 없다. 오히려 작은 코드를 직접 돌려보면서, “아 이게 그 바이트코드로 바뀌어 실행되는 거구나” 하고 몸으로 익히는 편이 빠르다.

정리하면, 파이썬은 내 코드를 바이트코드로 한 번 정리한 뒤 가상 머신이 실행하고, 그 결과를 .pyc로 저장해 다음 실행을 빠르게 만든다. 복잡해 보여도 결국 ‘읽기 쉬운 코드’와 ‘컴퓨터가 알아듣는 말’ 사이를 부드럽게 잇기 위한 장치다. 이 한 장면만 머릿속에 그려둬도, 파이썬을 다루는 내내 든든한 배경지식이 된다. 원리는 거들 뿐이다. 일단 한 줄 써서 실행해보면, 이 흐름이 비로소 손에 잡힌다.

참고 자료

답글 남기기