“다른 파일의 함수를 가져다 쓰고 싶은데, 어떻게 해야 하나요?”
프로그램이 커질수록 코드를 여러 파일로 나누어 관리해야 합니다. Python의 모듈 시스템은 코드를 재사용하고 구조화하는 강력한 방법입니다. 이 글에서는 모듈의 개념부터 실전 활용법까지 완벽하게 알려드립니다.
모듈이란?
모듈의 개념
- *모듈(Module)**은 Python 코드를 담고 있는 파일입니다. 함수, 클래스, 변수 등을 담아 다른 프로그램에서 재사용할 수 있습니다.
간단히 말해, .py 확장자를 가진 Python 파일 = 모듈입니다.
왜 모듈을 사용할까?
# ❌ 모듈 없이 - 모든 코드가 한 파일에
# main.py (5000줄)
def calculate_area(width, height):
return width * height
def calculate_volume(width, height, depth):
return width * height * depth
def save_to_file(data, filename):
with open(filename, 'w') as f:
f.write(data)
def read_from_file(filename):
with open(filename, 'r') as f:
return f.read()
# ... 수백 개의 함수들 ...
# ✅ 모듈 사용 - 기능별로 분리
# geometry.py
def calculate_area(width, height):
return width * height
def calculate_volume(width, height, depth):
return width * height * depth
# file_handler.py
def save_to_file(data, filename):
with open(filename, 'w') as f:
f.write(data)
def read_from_file(filename):
with open(filename, 'r') as f:
return f.read()
# main.py
import geometry
import file_handler
area = geometry.calculate_area(10, 5)
file_handler.save_to_file(str(area), 'result.txt')
모듈 사용의 장점
- 코드 재사용성 증가
- 유지보수 편리
- 네임스페이스 분리
- 협업 용이
모듈 만들기
기본 모듈 생성
파일을 만들기만 하면 모듈이 됩니다!
calculator.py (모듈 파일)
"""
계산기 모듈
간단한 사칙연산 기능을 제공합니다.
"""
def add(a, b):
"""덧셈"""
return a + b
def subtract(a, b):
"""뺄셈"""
return a - b
def multiply(a, b):
"""곱셈"""
return a * b
def divide(a, b):
"""나눗셈"""
if b == 0:
raise ValueError("0으로 나눌 수 없습니다")
return a / b
# 모듈 레벨 변수
PI = 3.14159
VERSION = "1.0.0"
main.py (모듈 사용)
import calculator
result1 = calculator.add(10, 5)
result2 = calculator.multiply(3, 4)
print(result1) # 15
print(result2) # 12
print(calculator.PI) # 3.14159
클래스가 포함된 모듈
"""사람 정보를 관리하는 모듈"""
class Person:
"""사람 클래스"""
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
return f"안녕하세요, 저는 {self.name}이고 {self.age}살입니다."
class Student(Person):
"""학생 클래스"""
def __init__(self, name, age, student_id):
super().__init__(name, age)
self.student_id = student_id
def study(self, subject):
return f"{self.name}이(가) {subject}를 공부합니다."
# 모듈 레벨 함수
def create_person(name, age):
"""Person 인스턴스를 생성하는 팩토리 함수"""
return Person(name, age)
import person
# 클래스 사용
p = person.Person("김철수", 25)
print(p.introduce())
s = person.Student("이영희", 20, "2025001")
print(s.study("Python"))
# 팩토리 함수 사용
p2 = person.create_person("박민수", 30)
print(p2.introduce())
import 기본 문법
1. 기본 import
import math
result = math.sqrt(16) # 4.0
print(math.pi) # 3.141592653589793
2. 여러 모듈 import
import math
import random
import datetime
# 또는 한 줄로
import math, random, datetime # 가능하지만 권장하지 않음
3. as로 별칭 사용
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 긴 모듈명을 짧게
import very_long_module_name as vlmn
arr = np.array([1, 2, 3])
4. from으로 특정 요소만 import
from math import sqrt, pi, cos
# 모듈명 없이 바로 사용
result = sqrt(16) # math.sqrt(16) 대신
print(pi) # math.pi 대신
5. from import with as
from datetime import datetime as dt
now = dt.now() # datetime.datetime.now() 대신
6. 모든 것 import (주의!)
from math import *
# 모든 함수를 직접 사용 가능
result = sqrt(16)
print(pi)
# ⚠️ 권장하지 않음: 네임스페이스 오염
import 고급 활용
상대 경로 import
프로젝트 구조가 복잡할 때 상대 경로로 import합니다.
my_project/
├── main.py
├── utils/
│ ├── __init__.py
│ ├── math_utils.py
│ └── string_utils.py
└── models/
├── __init__.py
└── user.py
utils/math_utils.py
def add(a, b):
return a + b
def multiply(a, b):
return a * b
models/user.py
# 상대 경로 import
from ..utils import math_utils # 상위 디렉토리의 utils
class User:
def __init__(self, name, age):
self.name = name
self.age = age
def calculate_birth_year(self, current_year):
# math_utils 사용
return math_utils.subtract(current_year, self.age)
상대 경로 import 규칙
.: 현재 디렉토리..: 상위 디렉토리...: 상위의 상위 디렉토리
조건부 import
import sys
if sys.platform == 'win32':
import winsound # Windows 전용
def beep():
winsound.Beep(1000, 500)
else:
import os
def beep():
os.system('echo -e "\\\\a"') # Unix/Linux
beep()
선택적 import (try-except)
# 특정 패키지가 설치되어 있으면 사용, 없으면 대안 사용
try:
import numpy as np
USE_NUMPY = True
except ImportError:
USE_NUMPY = False
print("NumPy가 설치되지 않았습니다. 기본 기능만 사용합니다.")
def calculate_mean(numbers):
if USE_NUMPY:
return np.mean(numbers)
else:
return sum(numbers) / len(numbers)
지연 import
필요할 때만 import하여 시작 시간을 단축합니다.
def process_image(filename):
# 함수 호출 시에만 import
from PIL import Image
img = Image.open(filename)
return img.size
# PIL이 필요한 경우에만 import됨
\\init\\.py 이해하기
패키지 만들기
디렉토리를 패키지로 만들려면 __init__.py 파일이 필요합니다.
mypackage/
├── __init__.py
├── module1.py
└── module2.py
mypackage/module1.py
def function1():
return "Module 1"
mypackage/module2.py
def function2():
return "Module 2"
mypackage/\\init\\.py (비어있어도 됨)
# 패키지 초기화 코드
print("mypackage를 불러왔습니다")
# 편의를 위한 import
from .module1 import function1
from .module2 import function2
__version__ = "1.0.0"
__all__ = ['function1', 'function2']
사용 예시
import mypackage
# __init__.py에서 import했으므로 바로 사용 가능
result1 = mypackage.function1()
result2 = mypackage.function2()
print(mypackage.__version__) # 1.0.0
\\all\\ 변수
from package import * 시 어떤 것을 노출할지 제어합니다.
__all__ = ['public_function', 'PublicClass']
def public_function():
return "공개 함수"
def _private_function():
return "비공개 함수"
class PublicClass:
pass
class _PrivateClass:
pass
사용
from mymodule import *
public_function() # 작동
PublicClass() # 작동
# _private_function() # NameError
# _PrivateClass() # NameError
# 명시적 import는 가능
from mymodule import _private_function
_private_function() # 작동
내장 모듈 활용
Python은 다양한 내장 모듈을 제공합니다.
1. os – 운영체제 기능
import os
# 현재 작업 디렉토리
print(os.getcwd())
# 디렉토리 생성
os.makedirs('test_folder', exist_ok=True)
# 파일 목록
files = os.listdir('.')
print(files)
# 경로 조작
path = os.path.join('folder', 'subfolder', 'file.txt')
print(path) # folder/subfolder/file.txt
# 파일 존재 여부
if os.path.exists('myfile.txt'):
print("파일이 존재합니다")
# 환경 변수
home = os.environ.get('HOME')
2. sys – 시스템 관련
import sys
# Python 버전
print(sys.version)
# 명령행 인자
print(sys.argv) # ['script.py', 'arg1', 'arg2']
# 모듈 검색 경로
print(sys.path)
# 프로그램 종료
# sys.exit(0)
# 표준 출력/에러
sys.stdout.write("표준 출력\\\\n")
sys.stderr.write("에러 메시지\\\\n")
3. datetime – 날짜와 시간
from datetime import datetime, date, time, timedelta
# 현재 날짜와 시간
now = datetime.now()
print(now) # 2025-10-11 14:30:00
# 날짜 생성
birthday = date(1995, 5, 15)
# 시간 계산
tomorrow = now + timedelta(days=1)
next_week = now + timedelta(weeks=1)
# 포맷팅
formatted = now.strftime('%Y년 %m월 %d일 %H시 %M분')
print(formatted)
# 파싱
date_str = "2025-10-11"
parsed = datetime.strptime(date_str, '%Y-%m-%d')
4. random – 난수 생성
import random
# 정수 난수
num = random.randint(1, 100) # 1~100
# 실수 난수
float_num = random.random() # 0.0~1.0
# 리스트에서 선택
fruits = ['사과', '바나나', '오렌지']
choice = random.choice(fruits)
# 여러 개 선택
samples = random.sample(fruits, 2)
# 리스트 섞기
random.shuffle(fruits)
5. json – JSON 처리
import json
# 딕셔너리를 JSON 문자열로
data = {
'name': '김철수',
'age': 25,
'skills': ['Python', 'JavaScript']
}
json_str = json.dumps(data, ensure_ascii=False, indent=2)
print(json_str)
# JSON 문자열을 딕셔너리로
loaded = json.loads(json_str)
# 파일로 저장
with open('data.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
# 파일에서 읽기
with open('data.json', 'r', encoding='utf-8') as f:
loaded_data = json.load(f)
6. re – 정규표현식
import re
# 패턴 매칭
text = "이메일: user@example.com"
pattern = r'\\\\w+@\\\\w+\\\\.\\\\w+'
match = re.search(pattern, text)
if match:
print(match.group()) # user@example.com
# 모든 매치 찾기
text = "전화번호: 010-1234-5678, 010-9876-5432"
phones = re.findall(r'\\\\d{3}-\\\\d{4}-\\\\d{4}', text)
print(phones) # ['010-1234-5678', '010-9876-5432']
# 치환
text = "Hello World"
replaced = re.sub(r'World', 'Python', text)
print(replaced) # Hello Python
실전 모듈 구조
유틸리티 모듈 만들기
utils/file_utils.py
"""파일 처리 유틸리티"""
import os
import json
def read_text_file(filename):
"""텍스트 파일 읽기"""
try:
with open(filename, 'r', encoding='utf-8') as f:
return f.read()
except FileNotFoundError:
print(f"파일을 찾을 수 없습니다: {filename}")
return None
def write_text_file(filename, content):
"""텍스트 파일 쓰기"""
with open(filename, 'w', encoding='utf-8') as f:
f.write(content)
def read_json_file(filename):
"""JSON 파일 읽기"""
with open(filename, 'r', encoding='utf-8') as f:
return json.load(f)
def write_json_file(filename, data):
"""JSON 파일 쓰기"""
with open(filename, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def get_file_size(filename):
"""파일 크기 반환 (bytes)"""
return os.path.getsize(filename)
def file_exists(filename):
"""파일 존재 여부"""
return os.path.exists(filename)
utils/string_utils.py
"""문자열 처리 유틸리티"""
def reverse_string(text):
"""문자열 뒤집기"""
return text[::-1]
def count_words(text):
"""단어 개수 세기"""
return len(text.split())
def capitalize_words(text):
"""각 단어의 첫 글자를 대문자로"""
return ' '.join(word.capitalize() for word in text.split())
def remove_whitespace(text):
"""공백 제거"""
return ''.join(text.split())
def truncate(text, length, suffix='...'):
"""문자열 자르기"""
if len(text) <= length:
return text
return text[:length] + suffix
utils/\\init\\.py
"""유틸리티 패키지"""
from .file_utils import (
read_text_file,
write_text_file,
read_json_file,
write_json_file
)
from .string_utils import (
reverse_string,
count_words,
capitalize_words
)
__version__ = '1.0.0'
__all__ = [
'read_text_file',
'write_text_file',
'read_json_file',
'write_json_file',
'reverse_string',
'count_words',
'capitalize_words'
]
from utils import read_json_file, capitalize_words
# 간편하게 사용
data = read_json_file('config.json')
text = capitalize_words("hello python world")
print(text) # Hello Python World
\\name\\ == “\\main\\” 이해하기
모듈이 직접 실행되는지, import되는지 구분합니다.
def add(a, b):
return a + b
def subtract(a, b):
return a - b
# 이 부분은 직접 실행할 때만 동작
if __name__ == "__main__":
print("Calculator 모듈을 직접 실행했습니다")
print("10 + 5 =", add(10, 5))
print("10 - 5 =", subtract(10, 5))
테스트
# 직접 실행
$ python calculator.py
Calculator 모듈을 직접 실행했습니다
10 + 5 = 15
10 - 5 = 5
# import해서 사용
import calculator
result = calculator.add(3, 4) # if __name__ 블록은 실행 안 됨
실전 활용: 테스트 코드 작성
# math_utils.py
def factorial(n):
"""팩토리얼 계산"""
if n <= 1:
return 1
return n * factorial(n - 1)
def fibonacci(n):
"""피보나치 수열"""
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
# 모듈 테스트
if __name__ == "__main__":
# 직접 실행 시 자동 테스트
print("=== 테스트 시작 ===")
assert factorial(5) == 120, "factorial 테스트 실패"
assert factorial(0) == 1, "factorial 테스트 실패"
print("✓ factorial 테스트 통과")
assert fibonacci(10) == 55, "fibonacci 테스트 실패"
assert fibonacci(0) == 0, "fibonacci 테스트 실패"
print("✓ fibonacci 테스트 통과")
print("=== 모든 테스트 통과 ===")
모듈 검색 경로
Python은 다음 순서로 모듈을 찾습니다:
- 현재 디렉토리
- PYTHONPATH 환경 변수
- 표준 라이브러리 디렉토리
- site-packages (설치된 패키지)
sys.path 확인
import sys
print("모듈 검색 경로:")
for path in sys.path:
print(f" - {path}")
경로 추가
import sys
import os
# 특정 디렉토리를 모듈 검색 경로에 추가
custom_path = os.path.join(os.getcwd(), 'my_modules')
sys.path.append(custom_path)
# 이제 my_modules 디렉토리의 모듈을 import 가능
import custom_module
순환 import 문제 해결
문제 상황
module_a.py
import module_b
def function_a():
return "A" + module_b.function_b()
module_b.py
import module_a # 순환 import!
def function_b():
return "B" + module_a.function_a()
해결 방법 1: 지연 import
# module_a.py
def function_a():
import module_b # 함수 내부에서 import
return "A" + module_b.function_b()
해결 방법 2: 구조 개선
# common.py
def shared_function():
return "공통 기능"
# module_a.py
import common
def function_a():
return "A" + common.shared_function()
# module_b.py
import common
def function_b():
return "B" + common.shared_function()
타사 패키지 관리
pip로 패키지 설치
# 패키지 설치
pip install requests
pip install pandas numpy
# 특정 버전 설치
pip install django==4.2.0
# 업그레이드
pip install --upgrade requests
# 제거
pip uninstall requests
# 설치된 패키지 목록
pip list
# requirements.txt 생성
pip freeze > requirements.txt
# requirements.txt로 일괄 설치
pip install -r requirements.txt
requirements.txt 예시
requests==2.31.0
pandas==2.1.0
numpy==1.25.2
flask==3.0.0
가상환경 사용
# 가상환경 생성
python -m venv myenv
# 활성화 (Windows)
myenv\\\\Scripts\\\\activate
# 활성화 (Mac/Linux)
source myenv/bin/activate
# 비활성화
deactivate
모듈 배포하기
setup.py 작성
# setup.py
from setuptools import setup, find_packages
setup(
name='mypackage',
version='1.0.0',
author='Your Name',
author_email='your@email.com',
description='패키지 설명',
long_description=open('README.md').read(),
long_description_content_type='text/markdown',
url='<https://github.com/yourusername/mypackage>',
packages=find_packages(),
classifiers=[
'Programming Language :: Python :: 3',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
],
python_requires='>=3.7',
install_requires=[
'requests>=2.25.0',
'numpy>=1.20.0',
],
)
배포
# 패키지 빌드
python setup.py sdist bdist_wheel
# PyPI에 업로드
pip install twine
twine upload dist/*
자주 하는 실수와 해결법
실수 1: 표준 라이브러리와 같은 이름
# ❌ 잘못된 예: random.py 파일 생성
# random.py
def my_function():
pass
# main.py
import random # 표준 라이브러리 대신 random.py를 import!
# random.randint(1, 10) # AttributeError!
해결: 표준 라이브러리 이름 피하기
실수 2: \\init\\.py 누락
mypackage/
├── module1.py # __init__.py가 없음!
└── module2.py
# import mypackage.module1 # ModuleNotFoundError!
해결: __init__.py 파일 추가 (비어있어도 됨)
실수 3: 상대 경로 import 오류
# ❌ 최상위 스크립트에서 상대 경로 import
# main.py
from . import utils # ValueError!
# ✅ 절대 경로 사용
import utils
마무리하며
Python 모듈 시스템은 코드를 구조화하고 재사용하는 핵심 기능입니다.
핵심 요약
- 모듈: Python 파일 (.py)
- 패키지: 모듈을 담은 디렉토리 (\\init\\.py 포함)
- import: 모듈을 가져와 사용
- from import: 특정 요소만 가져오기
- \\name\\: 실행 방식 구분
모듈 설계 원칙
- 하나의 모듈은 하나의 책임
- 명확하고 직관적인 이름
- 문서화 (docstring) 작성
- \_\all\\_로 공개 API 명시
- 순환 import 방지
실무 체크리스트
- ✅ 기능별로 모듈 분리
- ✅ \\init\\.py로 패키지 구성
- ✅ requirements.txt로 의존성 관리
- ✅ 가상환경 사용
- ✅ 테스트 코드 작성
모듈을 잘 활용하면 코드의 품질과 유지보수성이 크게 향상됩니다. 작은 프로젝트부터 모듈화를 실천해보세요!
참고 자료
- Python 공식 문서 – 모듈: https://docs.python.org/ko/3/tutorial/modules.html
- Python 공식 문서 – 패키지: https://docs.python.org/ko/3/tutorial/modules.html#packages
- Python 패키지 인덱스 (PyPI): https://pypi.org/