간단하게, 지뢰 찾기 게임을 모듈화 해봤습니다.
클래스끼리 독립시키고 각각의 모듈 Game.py와 Board.py에 상수가 필요하니 그것을 각각의 모듈에 지정해주지 않고,
상수전용 모듈을 만들어서 Game모듈과 Board모듈이 각각 상수모듈 Constants만 참조하게 해서 서로 호출할 때 상수만 바라보게 되면서 순환 참조(Circular Import)를 방지하는 상태를 만들게되었습니다.
이것은 의도해서 나온 결과는 아니지만, 상수를 또 하나의 모듈로 만들어서 그냥 그것을 참조하면 간단하지 않나? 이 생각에서 출발했는데 순환 참조를 방지할 수 있다는 점에서 큰 소득이 있었습니다.
모듈화를 하면서 좋은 점은 아래와 같습니다.
- 알 필요 없는 정보 차단 : Game 모듈 입장에서 중요한 건 지뢰가 잘 깔렸는가?이지 그걸 random모듈로 깔았는지 정해진 패턴으로 깔았는지 알 필요가 없습니다. 이렇게 하면 gmae.py의 상단 import 구문이 깔끔해지겠지요
- 도구 상자 분리 : 만약 나중에 지뢰를 랜덤이 아니라 유저가 설정한 위치에 깔고 싶다라고 요구 사항이 바뀌면 board.py 내부 로직만 수정하면 됩니다. game.py는 random 모듈을 쓰지 않았으니 고칠 게 없게 되겠죠
- 네임스페이스 청정구역화 : 모든 파일에 import random, import sys 등 다 넣어 버리면 나중에 어떤 파일이 어떤 도구를 쓰는지 파악하기 어려워질 수 있습니다. 지금은 3개의 모듈을 사용하고 있지만, 코딩이 점점 복잡해지면 복잡해질수록 다양한 라이브러리, 모듈을 사용하게 될 텐데 이러한 점을 방지할 수 있습니다. 지금처럼 난수는 오직 Board에서만 발생한다 라는 규칙이 생기면 나중에 난수 관련 버그가 생겼을 땐 고민할 필요 없이 board.py만 열어보면 되니 유지 보수 측면에서도 아주 훌륭하겠죠
Python을 공부하며 새로운 개념이 나왔으니 한번 짚고 넘어가 보겠습니다.
바로 순환 참조라는 개념입니다.
순환 참조(Circular Import) 간단하게 설명하면 "닭이 먼저냐, 달걀이 먼저냐"의 싸움에 Python 인터프리터가 끼어버린 상황을 말합니다. 모듈화 과정에서 이 문제가 왜 발생하는지, 그리고 왜 지금 구조가 안전한지 아래 설명을 통해 알아봅시다.
- 순환 참조가 발생하는 근본적인 이유 : 미완성 상태에서의 호출
- 파이썬은 모듈을 import 할 때 해당 파일을 처음부터 끝까지 한번 실행합니다. 이 과정에서 문제가 발생합니다.
- A 파일을 읽기 시작함. 중간에 import B를 만남.
- 파이썬은 A를 읽다 말고 B 파일로 점프함
- B 파일을 읽기 시작함. 그런데 중간에 import A를 만남.
- 파이썬은 다시 A파일을 읽으려 함.
- 문제 발생 : 파이썬 입장에서는 "이미 A를 읽고 있는 중인데 또 A를 읽으라고?" 혹은 "A는 아직 다 안 읽어서(정의 안되어서) 쓸 수가 없는데?"라고 판단하며 에러를 냅니다.지뢰 찾기에서의 상황
- 파이썬은 모듈을 import 할 때 해당 파일을 처음부터 끝까지 한번 실행합니다. 이 과정에서 문제가 발생합니다.
- 지뢰찾기 모듈화에서 문제상황
- 만약 상수를 따로 빼지 않고 Game과 Board끼리 해결하려고 했을 때 아래와 같은 상황이 일어났습니다.
- board.py : 지뢰를 심으면 MINE_COUNT가 필요한데 이건 게임의 설정이니까 from game import MINE_COUNT 해야지.
- game.py : 게임을 시작하려면 보드가 필요하니까 from board import Board 해야지.
- 실행 결과 :
- game.py 실행 → import Board 발견 → board.py로 이동.
- board.py 실행 → import MINE_COUNT 발견 → game.py로 이동.
- 에러 발생
- 만약 상수를 따로 빼지 않고 Game과 Board끼리 해결하려고 했을 때 아래와 같은 상황이 일어났습니다.
- 상수 모듈이 이 문제를 해결한 케이스
- constants.py가 의존성의 방향을 일방통행으로 만들었기 때문에 이러한 에러를 해결할 수 있었습니다.
- constants.py는 아무도 부르지 않은 독립적인 상태입니다.
- board.py : 오직 constants.py만 바라보게 됩니다. Game이 누군지 알필요도 관심도 없죠
- game.py : board.py와 constants.py를 둘 다 바라봅니다.
- 따라서 최상층(Game)은 아래층(Board, Constants)을 알 수 있지만, 아래층은 위층을 절대 불러서는 안 된다. 이것만 지키면 순환 참조는 절대 일어나지 않는다고 합니다.
- constants.py가 의존성의 방향을 일방통행으로 만들었기 때문에 이러한 에러를 해결할 수 있었습니다.
정리하자면 순환 참조는 서로가 서로를 필요로 할 때 발생합니다. 이를 방지하려면 두 모듈이 공통으로 필요한 정보(상수 등)를 제3의 장소(constants.py)로 빼버리거나, 한쪽이 다른 한쪽을 몰라도 되게끔 설계를 해야 한다고 합니다.
자, 이렇게 모듈화를 해서 game.py에서 실행을 하면 정상적으로 게임이 출력되는 것을 확인할 수 있습니다.

클래스단위로 모듈화를 시키는 것은 어렵지 않았으나, 만약 클래스 안에서 메서드를 추출하여 모듈화를 시킨다면? 정말 어려울 거 같아요. 앞으로도 여러 시도를 해보면서 python과 친해져 보도록 하겠습니다. 감사합니다.
'Python > 게임' 카테고리의 다른 글
| [Python] 지뢰찾기 만들기 회고 (0) | 2026.03.12 |
|---|---|
| [Python] 테트리스 만들기 회고 (0) | 2026.03.10 |