Python 코드를 실행하면 무슨 일이 일어날까?
Source: Dev.to
간단한 예제
간단한 파이썬 프로그램부터 시작해 보겠습니다. greet.py 라는 파일이 컴퓨터에 저장되어 있다고 가정합니다. 이 파일 안에는 greet() 라는 함수 하나가 있습니다:
# greet.py
def greet(name: str):
print(f"Hello {name}!")
이 함수를 인수 "drani" 로 호출하면:
greet(name="drani")
프로그램은 다음과 같이 출력합니다:
Hello drani!
파이썬 프로그램 실행하기
프로그램을 실행할 때 보통 다음 명령을 사용합니다:
python greet.py
이 명령이 실행되면 여러 단계가 백그라운드에서 일어납니다.
1. 코드 로드
파이썬 인터프리터(CPython)는 디스크에 있는 소스 파일을 메모리로 읽어들여 실행 준비를 합니다.
2. 바이트코드로 컴파일
인터프리터는 내부 컴파일러를 호출하여 다음과 같은 과정을 수행합니다:
- 토큰화: 소스 코드를 의미 있는 기호(토큰)로 분할합니다.
- 추상 구문 트리(AST) 구축: 토큰들을 프로그램 로직을 나타내는 트리 구조로 조직합니다.
- 바이트코드 컴파일: AST를 파이썬 바이트코드라는 낮은 수준의 표현으로 변환합니다. 인터프리터가 효율적으로 실행할 수 있도록 합니다.
__pycache__ 디렉터리 안에 .pyc 파일 형태로 바이트코드 캐시가 이미 존재한다면, 파이썬은 소스 파일을 다시 컴파일하는 대신 해당 캐시를 로드하여 실행 속도를 높일 수 있습니다.
3. 바이트코드 실행
CPython 가상 머신은 바이트코드를 한 명령어씩 실행합니다. 각 opcode에 대해:
- 인터프리터는 해당 opcode를 구현하는 C 함수에 전달합니다.
- 이 C 함수들은 CPU가 이해할 수 있는 네이티브 머신 코드로 컴파일됩니다.
- CPU는 이 명령들을 가져와(fetch) 디코드하고 실행하며, 필요에 따라 메모리상의 파이썬 객체를 조작합니다.
이 과정은 모든 명령이 실행될 때까지 계속됩니다.
4. 출력 생성
실행이 끝나면 결과값이 메모리에 저장됩니다. 프로그램에 print() 같은 출력 명령이 포함되어 있으면, 그 결과가 화면에 표시됩니다.
결론
greet.py 와 같은 간단한 프로그램이라도 파일 로드, 바이트코드 컴파일, 머신 레벨 명령 실행이라는 여러 단계의 처리를 거칩니다. 파이썬은 이러한 복잡성을 대부분 숨겨 주어 코드를 쉽게 작성하고 실행할 수 있게 하면서도 효율적이고 강력하게 동작합니다. 이 과정을 이해하면 더 효율적인 프로그램을 작성하고, 성능 문제를 해결하며, 오류가 발생했을 때 원인을 파악하는 데 도움이 됩니다.