
이미지 출처: Pexels · cottonbro studio · Pexels License
계산기 스크립트가 213줄이 됐습니다. 위쪽 절반은 세금과 할인을 계산하는 함수들이고, 아래쪽 절반은 그 결과를 화면에 찍는 부분입니다. 할인율 하나 고치려고 스크롤을 한참 내리다가 엉뚱한 함수를 건드린 것이 이번 주에만 두 번.
오늘 이 파일을 둘로 가릅니다. 계산은 calc.py가 맡고, 부르는 쪽은 main.py가 맡습니다. 끝나면 main.py 하나만 돌려도 이렇게 나옵니다.
calc 모듈이 읽혔습니다
5
0.1
calc
네 줄인데 내용은 전부 옆 파일 것입니다. 첫 줄은 calc.py가 스스로 찍은 것이고, 나머지 셋은 main.py가 calc.py에서 꺼내 온 값입니다. 파일을 나눴는데 값은 건너옵니다. 그 다리가 import 한 줄입니다.
모듈과 import가 뭔가요 — 정의부터
파이썬 공식 자습서는 모듈을 "파이썬 정의와 문장들을 담고 있는 파일"이라고 정의합니다. 파일 이름이 곧 모듈 이름이고, 확장자 .py를 뺀 부분이 그 이름입니다. calc.py를 만들면 모듈 이름은 calc입니다. 특별한 선언도, 등록 절차도 없습니다. 파일을 만들면 그게 모듈입니다.
import는 그 모듈을 지금 파일로 데려오는 문장입니다. 자습서는 import가 모듈 이름을 현재 이름 공간에 들여놓는다고 적었습니다. 이름 공간은 "이름과 값을 짝지어 둔 목록"입니다. import calc 한 줄이면 내 파일의 목록에 calc라는 이름표가 하나 생기고, 그 이름표를 통해 calc.add처럼 안쪽 것들에 닿습니다.
왜 나누느냐면, 같은 계산을 다른 프로그램에서도 쓰려면 복사해 붙이는 수밖에 없기 때문입니다. 복사본이 셋이 되면 고칠 자리도 셋이 됩니다. 파일 하나로 두고 세 프로그램이 불러 쓰면 고칠 자리는 하나.
성질은 이렇습니다.
| 성질 | 뜻 |
|---|---|
파일 이름에서 .py를 뺀 것이 모듈 이름 | calc.py → calc |
import는 그 파일을 위에서 아래로 한 번 실행한다 | 함수 정의뿐 아니라 print도 그때 돈다 |
| 같은 모듈을 여러 번 import해도 실행은 한 번 | 두 번째부터는 이미 읽어 둔 것을 준다 |
| 찾는 순서는 실행 중인 파일이 있는 폴더가 먼저 | 표준 모듈보다 내 폴더가 앞선다 |
이 글에서 쓰는 말입니다.
| 용어 | 뜻 |
|---|---|
| 모듈 | 파이썬 코드가 든 .py 파일 하나 |
| 표준 모듈 | 파이썬을 깔면 같이 딸려 오는 모듈. math, random, datetime 같은 것들 |
| 이름 공간 | 지금 파일에서 쓸 수 있는 이름들의 목록 |
| 점 표기 | calc.add처럼 모듈 이름 뒤에 점을 찍어 안쪽 것을 가리키는 방식 |
| 별명 | import calc as c의 c처럼 짧게 붙여 쓰는 다른 이름 |
앞의 창고 사진이 이 구조 그대로입니다. 선반 칸마다 이름표가 붙어 있고, 필요한 것을 꺼낼 때는 이름표를 보고 손을 뻗습니다. import는 선반 하나를 내 작업대 옆으로 끌어오는 일이고, from은 그 선반에서 나사 한 봉지만 집어 오는 일입니다. 선반째 끌어오면 뭐가 어디서 왔는지 이름표로 보이고, 봉지만 집어 오면 손이 짧아지는 대신 출처가 안 보입니다. 이 차이가 뒤에서 사고를 냅니다.
파일을 둘로 나눠 봅니다
같은 폴더에 파일 두 개를 만듭니다. 먼저 계산을 맡을 calc.py를 씁니다.
print("calc 모듈이 읽혔습니다")
TAX = 0.1
def add(a, b):
return a + b
def total(price, count):
return price * count
맨 위의 print는 원래 필요 없는 줄입니다. 언제 실행되는지 눈으로 보려고 일부러 넣었습니다. 뒤에서 뺍니다.
그 다음은 부르는 쪽 main.py입니다.
import calc
print(calc.add(2, 3))
print(calc.TAX)
print(calc.__name__)
main.py를 실행합니다.
calc 모듈이 읽혔습니다
5
0.1
calc
main.py 어디에도 print("calc 모듈이 읽혔습니다")가 없는데 첫 줄에 찍혔습니다. import calc가 calc.py를 위에서 아래로 한 번 훑고 지나갔기 때문입니다. 함수 정의 두 개와 변수 TAX 하나가 그때 만들어졌고, 중간에 있던 print도 같이 실행됐습니다.
그 아래 세 줄은 점 표기입니다. calc.add는 "calc 선반에 있는 add", calc.TAX는 "calc 선반에 있는 TAX". 마지막 calc.__name__은 모듈이 자기 이름을 적어 두는 자리이고, 여기서는 calc가 나옵니다. 이 값이 뒤에서 한 번 더 쓰입니다.
두 파일은 같은 폴더에 있어야 합니다. main.py만 바탕화면에 두고 calc.py를 문서 폴더에 두면 못 찾습니다. 이유는 다섯 번째 절에서 봅니다.
import 한 줄은 파일 전체를 한 번만 실행합니다
그럼 두 번 import하면 두 번 실행될까요. 해 봅니다.
import calc
import calc
print("두 번 import 했습니다")
print(calc.total(10, 3), calc.TAX)
calc 모듈이 읽혔습니다
두 번 import 했습니다
30 0.1
import calc가 두 줄인데 "calc 모듈이 읽혔습니다"는 한 번만 찍혔습니다. 파이썬은 한 번 읽은 모듈을 기억해 두고, 두 번째부터는 읽어 둔 것을 그대로 건넵니다. 두 번 쓰든 열 번 쓰든 같습니다. 자습서도 모듈 초기화 코드는 처음 import될 때만 실행된다고 못박아 뒀습니다.
덕분에 파일 열 개가 같은 모듈을 import해도 무거워지지 않습니다. 대신 함정이 하나. 프로그램을 돌려 놓은 상태에서 calc.py를 고쳐도 반영되지 않습니다. 이미 읽어 둔 것을 쓰니까요. 고쳤으면 프로그램을 다시 시작해야 합니다. 처음 모듈을 나눠 쓸 때 "분명히 고쳤는데 그대로인데요" 하는 상황이 거의 이것입니다.
모듈이 실제로 무엇인지도 확인할 수 있습니다.
import calc
print(type(calc))
print(calc)
<class 'module'>
<module 'calc' from 'C:\\...\\run\\calc.py'>
calc는 문자열도 함수도 아닌 module 타입의 값이고, 어느 파일에서 왔는지 경로까지 달고 있습니다. 리스트나 딕셔너리처럼, 모듈도 변수에 담기는 값 하나입니다.
여기서 calc.py의 print 줄을 빼야 합니다. 그런데 calc.py만 따로 돌려 시험할 때는 그런 출력이 있는 편이 편합니다. 둘 다 되게 하는 관용구가 있습니다.
if __name__ == "__main__":
print("calc 를 직접 실행했습니다")
calc.py를 직접 실행하면 그 파일의 __name__은 "__main__"이 되고, 다른 파일이 import해서 들어오면 "calc"가 됩니다. 아까 main.py에서 calc.__name__을 찍었을 때 calc가 나온 것이 그 증거입니다. 그래서 이 if 아래에 둔 줄은 직접 실행할 때만 돌고, import될 때는 건너뜁니다. 시험용 출력이나 예제 코드를 여기에 넣어 둡니다.
필요한 것만 골라 오기 — from과 as
calc.add, calc.TAX, calc.total. 점 표기가 길다 싶으면 필요한 이름만 직접 가져올 수 있습니다.
from calc import add, TAX
print(add(1, 2), TAX)
print(calc.add(1, 2))
calc 모듈이 읽혔습니다
3 0.1
NameError: name 'calc' is not defined
앞의 두 값은 잘 나왔습니다. add와 TAX를 점 없이 바로 씁니다. 그런데 마지막 줄에서 NameError. from calc import add, TAX는 add와 TAX라는 이름표만 내 목록에 놓습니다. calc라는 이름표는 놓지 않습니다. 모듈은 읽히지만(그래서 첫 줄이 찍혔습니다) 그 이름으로 부를 수는 없습니다.
이름이 마음에 안 들면 as로 바꿔 답니다.
import calc as c
from calc import total as 합계
print(c.add(4, 5))
print(합계(1200, 3))
9
3600
import calc as c는 선반을 c라는 짧은 이름표로 끌어옵니다. from calc import total as 합계는 함수 하나를 가져오면서 이름을 바꿔 답니다. 남들이 import pandas as pd, import numpy as np라고 쓰는 것이 이 문법입니다.

같은 파일을 읽어도 내 목록에 남는 이름표는 다릅니다.
셋 중 무엇을 쓸지는 취향이 아니라 읽는 사람 기준으로 정합니다. 저는 import 모듈 쪽을 기본으로 씁니다. add(1, 2)만 보이면 이 add가 어디서 왔는지 파일을 뒤져야 하지만, calc.add(1, 2)는 그 자리에서 답이 나옵니다. from은 from datetime import date처럼 아주 자주 쓰는 한두 개에만 씁니다.
from calc import *처럼 별표로 전부 가져오는 문법도 있습니다. 자습서는 이 방식이 이미 정의해 둔 이름을 덮어쓸 수 있어 일반적으로 좋지 않게 여겨진다고 적었습니다. 쓰지 않는 쪽으로 배우는 편이 낫습니다.
파일 이름을 random.py로 지었더니
로또 번호를 뽑는 연습을 합니다. 파일 이름은 lotto.py.
import random
print(random.randint(1, 10))
1
잘 됩니다. 이제 난수 관련 실험을 따로 정리하려고, 같은 폴더에 메모용 파일을 하나 더 만듭니다. 이름은 알아보기 쉽게 random.py로 정합니다.
print("내가 만든 random.py 입니다")
그리고 아까 잘 되던 lotto.py를 다시 돌립니다.
내가 만든 random.py 입니다
Traceback (most recent call last):
File "...\lotto.py", line 2, in <module>
print(random.randint(1, 10))
^^^^^^^^^^^^^^
AttributeError: module 'random' has no attribute 'randint' (consider renaming
'...\random.py' since it has the same name as the standard library module named
'random' and prevents importing that standard library module)
lotto.py는 한 글자도 안 고쳤는데 터졌습니다. 옆에 파일 하나를 만들었을 뿐입니다.
import random을 만난 파이썬이 random이라는 이름의 모듈을 찾아 나섰고, 제일 먼저 뒤진 곳이 지금 돌리는 파일이 있는 폴더였습니다. 거기 random.py가 있으니 그걸 집었고, 표준 random은 쳐다보지도 않았습니다. 그래서 첫 줄에 "내가 만든 random.py 입니다"가 찍혔고, 그 안에 randint가 없으니 AttributeError가 났습니다.
찾는 순서는 sys.path라는 목록에 들어 있습니다.
import sys
print(len(sys.path), "곳을 순서대로 뒤집니다")
print("첫 칸:", repr(sys.path[0]))
for p in sys.path[1:4]:
print(" -", p)📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
첫 칸이 빈 문자열이거나 실행 중인 스크립트의 폴더입니다. 자습서도 인터프리터가 입력 스크립트가 있는 디렉터리를 먼저 찾고 그 다음에 표준 라이브러리 경로를 본다고 설명합니다. 내 폴더가 언제나 앞입니다.

1번이 내 폴더입니다. 거기서 찾으면 2번 표준 모듈까지 차례가 가지 않습니다.
그래서 파일 이름 짓기가 규칙이 됩니다. random.py, math.py, time.py, json.py, email.py, test.py, string.py. 표준 모듈과 같은 이름은 피합니다. 헷갈리면 my_random.py, lotto_util.py처럼 앞뒤에 뭔가를 붙입니다. 파이썬이 친절하게 이름을 바꿔 보라고 알려 주긴 하지만, 이 힌트가 안 나오는 경우도 있습니다. 표준 모듈을 import하지 않고 내 파일만 조용히 쓰고 있으면 에러 없이 엉뚱하게 동작합니다.
한 가지 더. 폴더에 __pycache__가 생기고 그 안에 calc.cpython-314.pyc 같은 파일이 보일 텐데, 파이썬이 읽어 둔 것을 다음번에 빨리 쓰려고 저장해 둔 것입니다. 지워도 되고 그냥 둬도 됩니다. 손으로 고칠 파일은 아닙니다.
에러 두 줄을 읽습니다
모듈 쪽에서 만나는 에러는 크게 둘입니다. 이름이 다릅니다.
이름 자체를 못 찾으면 ModuleNotFoundError입니다.
try:
import 없는모듈
except ModuleNotFoundError as e:
print(type(e).__name__)
print(e)📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
ModuleNotFoundError
No module named '없는모듈'
파일 이름 오타, 다른 폴더에 둔 경우, 아직 설치하지 않은 외부 라이브러리가 여기 해당합니다. 오타부터 보고, 그 다음 두 파일이 같은 폴더에 있는지 봅니다.
모듈은 찾았는데 그 안에 없는 것을 꺼내려 하면 AttributeError입니다. 아까 random.randint가 그랬습니다. 이 에러가 나면 "내가 부른 그 모듈이 정말 내가 생각한 그 모듈인가"를 의심합니다. 확인은 한 줄이면 됩니다.
import random
print(random.__file__)
표준 random이면 파이썬 설치 폴더 안쪽 경로가 나오고, 내 파일이 가로챘으면 작업 폴더 경로가 나옵니다.

긴 에러에서 실제로 읽을 곳은 뒤쪽 괄호 안입니다.
에러 메시지가 길다고 넘기지 않는 편이 좋습니다. 파이썬은 원인 짐작까지 적어 주는데, 그 문장이 대개 마지막 줄 괄호 안에 있습니다.
표준 모듈은 이미 선반에 있습니다
직접 만든 모듈만 import하는 것은 아닙니다. 파이썬을 깔면 따라오는 모듈이 200개가 넘습니다. 설치도 필요 없습니다.
import math
import random
import datetime
print(math.sqrt(16))
print(math.floor(3.7), math.ceil(3.2))
print(len(random.sample(range(1, 46), 6)))
print(random.choice(["아메리카노", "라떼", "녹차"]))
오늘 = datetime.date(2026, 9, 17)
print(오늘, "는 요일번호", 오늘.weekday())📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
4.0
3 4
6
(셋 중 무작위로 하나)
2026-09-17 는 요일번호 3
math.sqrt(16)이 4가 아니라 4.0으로 나온 것이 눈에 띕니다. 제곱근은 늘 실수로 돌려주니까요. weekday()가 돌려준 3은 목요일입니다. 월요일이 0이니 셋을 더하면 목요일.
어떤 모듈이 있는지는 외우는 게 아니라 필요할 때 찾습니다. "파이썬 날짜 차이", "파이썬 폴더 목록"처럼 하려는 일로 검색하면 표준 모듈 이름이 먼저 나옵니다. os는 파일과 폴더, json은 데이터 주고받기, csv는 표 파일, re는 문자열 패턴을 맡습니다. 시즌 4에서 자주 부르게 됩니다.
완성한 파일 두 개
처음의 213줄짜리 계산기를 정리한 결과입니다. calc.py부터.
"""가격 계산 함수 모음."""
TAX = 0.1
def add(a, b):
return a + b
def total(price, count):
return price * count
def with_tax(price):
return round(price * (1 + TAX))
if __name__ == "__main__":
print("calc.py 자체 점검")
print(add(2, 3), total(1200, 3), with_tax(10000))
맨 위 따옴표 세 개짜리 줄은 이 파일이 무엇을 하는지 적어 두는 자리입니다. 맨 아래 if 블록은 calc.py를 직접 돌릴 때만 실행되는 자체 점검이고요. 그리고 부르는 쪽 main.py.
import calc
가격 = 1200
개수 = 3
합계 = calc.total(가격, 개수)
print("합계", 합계)
print("세금 포함", calc.with_tax(합계))
print("세율", calc.TAX)
합계 3600
세금 포함 3960
세율 0.1
main.py에는 계산식이 한 줄도 없습니다. 세율을 8퍼센트로 바꿀 일이 생기면 calc.py의 TAX 한 줄만 고칩니다. 이 계산을 쓰는 프로그램이 셋으로 늘어도 고칠 자리는 여전히 하나.
문장마다 내 목록에 남는 것이 다릅니다.
| 하려는 일 | 쓰는 문장 | 결과 |
|---|---|---|
| 모듈 통째로 데려오기 | import calc | calc라는 이름표 하나. calc.add로 접근 |
| 필요한 것만 집어 오기 | from calc import add | add 이름표만. calc는 못 씀 |
| 짧은 이름으로 쓰기 | import calc as c | c 이름표만. calc는 못 씀 |
| 직접 실행할 때만 돌리기 | if __name__ == "__main__": | import될 때는 건너뜀 |
| 전부 가져오기 | from calc import * | 이름 충돌 위험. 권하지 않음 |
굳이 줄이면 이 정도입니다. import는 그 파일을 한 번 실행합니다. from으로 가져오면 모듈 이름표는 안 생깁니다. 그리고 파일 이름은 표준 모듈과 겹치지 않게 짓습니다.
출력을 맞혀 보면 어디서 갈리는지 보입니다
미니 퀴즈
참고 자료
- 파이썬 공식 자습서 6장 "모듈" — 모듈의 정의,
import가 이름 공간에 하는 일, 초기화 코드가 한 번만 실행되는 규칙 https://docs.python.org/ko/3/tutorial/modules.html - 같은 문서 6.1.1 "모듈 검색 경로" — 입력 스크립트가 있는 디렉터리를 먼저 찾는 순서와
sys.pathhttps://docs.python.org/ko/3/tutorial/modules.html - 같은 문서 6.4.1 — 별표로 전부 가져오는 방식을 권하지 않는 이유 https://docs.python.org/ko/3/tutorial/modules.html
- 파이썬 표준 라이브러리
random·math·datetime문서 https://docs.python.org/ko/3/library/index.html
포켓코딩(PYTHON2) 6편 · 5편(파이썬 함수 기본값과 가변 인자)에서 이어집니다. 예제 코드는 강사 개인 GitHub 저장소의 강의 자료와 파이썬 공식 자습서의 예제를 바탕으로 다시 썼고, 출력은 전부 Python 3.14에서 실행해 받아 적었습니다. 다음 편은 예외 처리입니다. try와 except로 에러를 받아 내는 법, finally가 언제 도는지, 그리고 except: 하나로 전부 잡으면 왜 위험한지 봅니다.