이번에는 Python과 MySQL을 연결해서 간단한 단어장 프로그램을 구현해보았다.
이 프로그램의 작동 원리는 다음과 같다.
- 사용자에게 메뉴를 보여준다 (단어 등록 ,조회 ,수정, 삭제 등 원하는 기능을 선택할 수 있다) (Menu)
- 사용자가 원하는 메뉴 번호를 선택한다
- 선택한 메뉴에 따라 해당 기능을 실행한다. (Service)
ㄴ 필요한 경우 MySQL DB에 데이터를 저장,수정하거나 조회한다. (WordsDAO)
💻 사용할 테이블 voca
이번 단어장 프로그램에서는 영어 단어, 뜻,그리고 레벨을 저장할 수 있는 voca 테이블을 이용 해보았다.
MySQLWorkbench 에서
select * from voca
를 실행하면 아래와 같이 결과가 나온다

1. Word 클래스 만들기
먼저 단어 하나의 정보를 관리하기 위해 Word 클래스를 만들었다.
이 프로그램에서 단어 하나는 영어 단어(eng) , 뜻(kor) , 레벨(lev) 정보를 함께 가진다.
그래서 이 값들을 하나의 객체로 묶어서 관리하도록 했다.
코드 1️⃣
class Word:
def __init__(self,eng,kor,lev=1):
self.eng=eng
self.kor=kor
self.lev=lev
def __repr__(self):
return f"Word(eng='{self.eng}' , kor='{self.kor}' , lev= {self.lev})"
👉 __init__()
Word 객체가 생성될 때 실행되는 생성자
새로운 단어를 만들 때 영어 단어 , 뜻 ,레벨 값을 받아서 객체 안에 저장해준다
👉 __repr__()
객체를 출력했을 때 좀 더 가독성 좋게 보여주기 위해 작성한 매직 메서드
코드 2️⃣
🔨 Word 클래스 : 객체의 속성에 getter 와 setter를 사용해 접근
@property # getter
def eng(self):
return self.__eng
@eng.setter
def eng(self,eng):
if not eng:
raise ValueError("영어 단어는 비워둘 수 없습니다")
else:
self.__eng=eng
@property
def kor(self):
return self.__kor
@kor.setter
def kor(self,kor):
if not kor:
raise ValueError("뜻을 비워둘 수 없습니다")
else:
self.__kor=kor
@property
def lev(self):
return self.__lev
@lev.setter
def lev(self,lev):
lev=int(lev)
if lev < 1 :
raise ValueError("레벨은 1 이상이여야 합니다")
else:
self.__lev=lev
2. WordsDAO 클래스 만들기
※ DAO : Data Access Object
데이터 베이스 접근을 담당하는 객체이다.
쉽게 말해,
- sql문을 실행
- 데이터를 저장 / 조회 / 수정 / 삭제
하는 역할을 담당하는 클래스이다.
WordsDAO 클래스는 MySQL과 연동하여 Python 코드 안에서 DB 연결(connect) 및 해제(disconnect)를 관리하고, SQL문을 실행할 수 있도록 구현했다.
코드 1️⃣
class WordsDAO: # Data Access Object
def __init__(self):
self.db = None
def connect(self):
# connect 실행 시 데이터베이스를 연결시킨다
self.db= MySQLdb.connect(host= 'localhost', user='apple',password ='1111',db='ai', charset='utf8')
def disconnect(self):
if self.db :
self.db.close()
👉 __init__()
DB 객체를 저장할 self.db 를 None으로 초기화했다.
👉 connect()
MySQLdb.connect() 를 이용해 Python과 MySQL을 연결
👉 disconnect() : DB 연결을 종료
이 클래스에서는 단어 등록, 조회, 검색, 수정, 삭제 기능을 담당하도록 구성했다.
우선 어떤 기능들이 있는 지 큰 구조부터 먼저 살펴보고, 이후 각 함수가 실제로 어떻게 동작하는지 하나씩 구현해보자.
# ✅ 단어 등록
def insert(self,word): # word : Word 객체
pass
# ✅ 단어 출력하기
def select_all(self):
pass
# ✅ 사용자가 입력한 것이 포함된 모든 단어들을 검색
def search_all(self,eng):
pass
# ✅ 사용자가 입력한 단어를 검색
def search(self,eng):
pass
# ✅ 특정 단어의 뜻과 레벨을 수정하는 함수
def update(self,word):
pass
# ✅ 특정 단어를 삭제하는 함수
def delete(self, eng):
pass
3. Menu 클래스 만들기
Menu 클래스는 사용자 입장에서 가장 먼저 마주하는 화면을 담당한다.
즉, 사용자에게 메뉴를 보여주고, 사용자가 선택한 번호에 따라 알맞은 기능을 실행시키는 역할을 한다.
아직 WordsService와 WordsDAO의 세부 기능을 모두 구현하지는 않았지만, 전체 프로그램이 어떤 흐름으로 동작해야 하는지 먼저 잡아보기 위해 Menu 클래스부터 작성해보았다.
Menu 클래스 전체 코드
class Menu:
def __init__(self):
self.service = WordsService()
def run(self):
while True:
try:
print()
print("===== 단어장 프로그램 =====")
print("1. 등록하기")
print("2. 출력하기")
print("3. 검색하기")
print("4. 수정하기")
print("5. 삭제하기")
print("6. 종료하기")
menu= int(input("메뉴를 선택하세요 "))
if menu == 1 :
print("단어를 등록합니다")
self.service.insert_word()
elif menu ==2 :
print("단어를 출력합니다")
self.service.print_all()
elif menu== 3 :
print("단어를 검색합니다")
self.sevice.search_words()
elif menu ==4 :
print("단어를 수정합니다")
self.service.edit_word()
elif menu == 5 :
print("단어를 삭제합니다")
self.sevice.delete_word()
elif menu == 6 :
print("프로그램을 종료합니다")
break
else:
print("메뉴는 1부터 6까지 입력해주세요")
except Exception as e:
print("오류:",e)
print('다시 입력하세요')
👉 내부에 WordsService 객체를 두고 선택한 메뉴에 따라 Service 클래스의 메서드를 호출하도록 했다.
def __init__(self):
self.service = WordsService()
👉 뒤에서 클래스를 만들면서 더 자세히 설명하겠지만, Menu 클래스가 직접 DB 작업을 처리하도록 하지 않고, 실제 기능을 WordsService에게 맡기는 것이다.
4. WordsService 클래스 만들기
이제 Menu에서 사용자가 선택한 기능을 실제로 처리해줄 WordsService 클래스를 만들어보자.
class WordsService: # db에 연결이 되어야 한다
def __init__(self):
self.dao = WordsDAO()
def insert_word(self):
pass
def print_all(self):
pass
def search_words(self):
pass
def edit_word(self):
pass
def delete_word(self):
pass
👉 WordsService 클래스 안에는 WordsDAO 객체를 생성해두었다. 이를 통해 DB 관련된 작업은 WordsDAO에게 맡길 수 있다.
정리하자면,
- WordsService : 기능의 흐름을 담당하는 클래스
- WordsDAO : 실제로 DB에 접근해서 SQL문을 실행하는 클래스
이다.
예를 들어, 단어 등록하는 기능을 생각해보면 다음과 같은 흐름으로 동작한다
- 사용자에게 영어단어, 뜻 ,레벨을 입력 받는다.
- 입력받은 값으로 Word 객체를 새로 생성한다.
- WordsDAO의 insert() 메서드를 호출한다.
- DAO에서 INSERT SQL문을 실행하여 DB에 저장한다.
👉 이처럼 WordsService는 사용자의 입력과 DB 작업 사이에서 중간 역할을 한다.
처음에는 Service 클래스의 역할이 좀 헷갈렸는데, 이 클래스는 기능을 어떤 순서로 실행할 지 정리해주는 클래스 라고 이해하면 될 거 같다.
이제 본격적으로 각 기능들을 하나씩 채워보자.
✅ 단어 등록 기능 구현하기
사용자가 Menu에서 1번(단어 등록) 을 선택하면 Menu 클래스에서는 WordsService 클래스의 insert_word() 함수를 호출하게 된다.
즉, 메뉴에서 아래 코드가 실행되는 것이다
if menu == 1 :
print("단어를 등록합니다")
self.service.insert_word()
이제 우리가 채워야 할 것은 2가지이다.
- WordsService의 insert_word()
- WordsDAO의 insert(word)
단어 등록 기능의 전체 흐름은 다음과 같다
사용자 입력 → insert_word() → Word 객체 생성 → dao.insert(word) → DB 저장
❶ WordsService의 insert_word() 구현
def insert_word(self):
eng= input("영어 단어를 입력하세요 :")
kor= input("뜻을 입력하세요:")
lev= input("LEVEL을 입력하세요")
word =Word(eng,kor,lev) # 새로 추가할 Word 객체 생성- 입력받은 데이터를 하나로 묶기
self.dao.insert(word) # 실제 DB 저장은 DAO에게 맡기기
print('단어가 등록되었습니다')
❷ WordsDAO의 insert(word) 기능 구현하기
앞에서 WordsService의 insert_word() 함수에서는 입력받은 값을 Word 객체로 만들어주었다.
이제 이 Word 객체를 실제 DB에 저장해야 한다.
def insert(self,word): # word : Word 객체
self.connect() # DB 연결
cur= self.db.cursor()
sql = 'insert into voca (eng,kor,lev) values(%s, %s ,%s)'
data= (word.eng, word.kor, word.lev) # word 객체안의 데이터를 tuple로 묶기
cur.execute(sql,data) # sql문 실행
self.db.commit() # 실제 데이터베이스에 적용
# 작업 종료 -> cursor & DB 연결 종료
cur.close()
self.disconnect()
✅ DB의 모든 단어들 출력하기
사용자가 Menu에서 2번(단어 출력) 을 선택하면 Menu 클래스에서는 WordsService 의 print_all() 함수를 호출하게 된다.
즉, 메뉴에서 아래 코드가 실행되는 것이다
elif menu ==2 :
print("단어를 출력합니다")
self.service.print_all()
이번에 구현해야 할 함수는 2가지이다
- WordsService의 print_all()
- WordsDAO의 select_all()
단어 출력 기능의 전체 흐름은 다음과 같다
사용자 입력 → WordsService.print_all() → WordsService.dao.select_all() → DB 조회 → 결과 반환 → 단어 출력
❶ WordsService 의 print_all()
이 함수에서는 DAO의 select_all() 함수를 호출해서 DB에 저장된 모든 단어를 가져온다.
def print_all(self):
words = self.dao.select_all()
if not words:
print("등록된 단어가 없습니다")
return
for word in words:
print(f"{word['eng']} 뜻:{word['kor']}, 레벨:{word['lev']}")
✔️
if not words:
print("등록된 단어가 없습니다")
return
👉 만약 DB에 저장된 단어가 하나도 없다면 출력할 데이터가 없기 때문에 예외 처리를 했다.
✔️
for word in words:
print(f"{word['eng']} 뜻:{word['kor']}, 레벨:{word['lev']}")
👉 조회된 데이터는 여러 개일 수 있기 때문에 for문을 사용해서 하나씩 출력하도록 했다.
여기서 word['eng']처럼 딕셔너리 형태로 접근하는 이유는 DAO에서 DictCursor를 사용했기 때문이다.
❷ WordsDAO 의 select_all()
def select_all(self):
self.connect()
cur = self.db.cursor(MySQLdb.cursors.DictCursor)
sql = "select eng, kor, lev from voca order by eng asc"
cur.execute(sql)
rows = cur.fetchall()
cur.close()
self.disconnect()
return rows
⁉️ DictCursor을 사용한 이유
조회한 결과를 컬럼 이름 기준으로 가져오기 위해서이다.
만약 일반 cursor를 사용하면 결과가 tuple 형태로 반환된다.
예를 들어
(‘apple’, ‘사과’,1)
이렇게 tuple 형태로 반환되기 때문에 index를 통해 접근해야 한다.
하지만, DictCursor를 사용하면 아래처럼 딕셔너리 형태로 데이터를 가져올 수 있다.
{ 'eng': 'apple', 'kor': '사과', 'lev': 1 }
이렇게 하면 word['eng'], word['kor']처럼 컬럼 이름으로 바로 접근할 수 있다.
👉 rows = cur.fetchall()
fetchall()은 조회된 데이터를 한 번에 모두 가져오는 함수이다.
즉, select 문 실행 결과를 리스트 형태로 받아오는 것이다.
👉 order by eng asc
영어 단어 기준 오름차순으로 정렬되도록 하였다.
✅ 단어 검색하기 기능
사용자가 Menu에서 3번(단어 검색) 을 선택하면 Menu 클래스에서는 WordsService 의 search_words() 함수를 호출하게 된다.
이번에 구현해야 할 함수는 두 가지이다.
- WordsService.search_words()
- WordsDAO.search_all()
단어 검색 기능의 전체 흐름은 다음과 같다
사용자 입력 → WordsService.search _words() → WordsDAO.search_all() → DB 조회 → 결과 반환 → 단어 출력
❶ WordsService의 search_words()
먼저 WordsService의 search_words() 함수부터 구현해보자.
def search_words(self):
## 사용자로부터 영단어를 입력받는다
eng = input("검색할 단어를 입력하세요: ")
words =self.dao.search_all(eng) # eng를 포함하는 모든 단어들을 검색한다
if not words :
print('찾는 단어가 없습니다')
return
for word in words:
print(f"{word['eng']} 뜻:{word['kor']}, 레벨:{word['lev']}")
✔️ 먼저 사용자가 검색할 영어 단어를 입력 받는다.
eng = input("검색할 단어를 입력하세요 : ")
✔️ 그 다음 DAO의 search_all() 함수에 사용자가 입력한 단어를 전달한다.
words = self.dao.search_all(eng)
👉 여기서는 단어를 완전히 일치하게 검색하는 것이 아니라, 입력한 문자열이 포함된 모든 단어를 검색하도록 구현했다.
❷ WordsDAO 의 search_all()
def search_all(self,eng):
self.connect() # DB 연결
cur=self.db.cursor(MySQLdb.cursors.DictCursor)
sql = "select eng, kor, lev from voca where eng like concat('%%',%s,'%%')" ## concat 이용
cur.execute(sql,(eng,)) # 커서 실행
rows = cur.fetchall()
cur.close()
self.disconnect()
return rows
✔️
sql = "select eng, kor, lev from voca where eng like concat('%%',%s,'%%')"
👉 이번 검색 기능에서는 사용자가 입력한 문자열이 포함된 단어들을 모두 조회하도록 구현했다.
SQL에서는 특정 문자열이 포함된 데이터를 검색할 때 LIKE 문법을 사용한다.
예를 들어 아래 SQL문은
where eng like ‘%app%
app라는 문자열이 포함된 단어들을 모두 검색한다.
👉 cur.execute(sql,(eng,))
여기서 (eng,) 처럼 쉼표를 붙인 것은 Python에서 tuple 형태로 전달하기 위해서이다.
✅ 단어 수정하기
단어 수정 기능에서는 총 3가지 함수를 구현해야 한다
- WordsService 의 edit_word()
- WordsDAO 의 search()
- WordsDAO 의 update(word)
❶ WordsService 의 edit_word()
def edit_word(self):
eng= input("수정할 단어를 입력하세요")
word = self.dao.search(eng) # 찾을 단어를 찾는다
if not word :
print('수정할 단어가 없습니다')
return
kor = input('새로운 뜻을 입력하세요')
lev = input('새로운 레벨을 입력하세요')
word =Word(eng,kor,lev)
result = self.dao.update(word)
if result > 0 :
print('수정되었습니다')
else:
print('수정 실패했습니다')
👉 먼저 수정할 단어를 입력받고 search() 함수를 통해 해당 단어가 존재하는지 확인한다.
👉 단어가 존재하면 새로운 뜻과 레벨을 입력받아 새로운 Word 객체를 생성한다.
👉 마지막으로 바뀐 단어 객체를 dao.update(word)에 전달하여 DB를 수정한다.
❷ WordsDAO 의 search()
def search(self,eng):
self.connect()
cur = self.db.cursor(MySQLdb.cursors.DictCursor)
sql = “select eng, kor ,lev from voca where eng = %s”
cur.execute(sql,(eng,))
row = cur.fetchone()
cur.close()
self.disconnect()
return row
👉 search_all()과 달리 이번 search() 함수는 입력한 단어가 정확히 존재하는지 확인하기 위해 사용했다.
따라서 LIKE 대신 = 연산자를 사용해서 완전히 일치하는 단어만 조회하도록 구현했다.
❸ WordsDAO 의 update(word)
def update(self,word):
self.connect()
cur = self.db.cursor(MySQLdb.cursors.DictCursor)
sql = 'update voca set kor= %s , lev= %s where eng= %s'
data = (word.kor, word.lev , word.eng)
result= cur.execute(sql,data)
self.db.commit()
cur.close()
self.disconnect()
return result
✅ 단어 삭제하기
단어 삭제 기능에서는 총 2가지 함수를 구현하면 된다.
- WordsService.delete_word()
- WordsDAO.delete(eng)
❶ WordsService 의 delete_word()
def delete_word(self):
eng = input('삭제할 단어를 입력하세요')
word = self.dao.search(eng)
if not word :
print('삭제할 단어가 없습니다')
return
result =self.dao.delete(eng)
if result > 0 :
print("삭제되었습니다")
else :
print("단어 삭제가 실패했습니다")
👉 삭제할 단어를 사용자로부터 입력받는다.
👉 search(eng)를 통해 해당 단어가 실제로 존재하는지 먼저 확인한다.
👉 단어가 존재하면 dao.delete(eng)를 호출하여 DB에서 삭제를 진행한다.
❷ WordsDAO의 delete()
def delete(self, eng):
self.connect()
cur= self.db.cursor()
sql = "delete from voca where eng = %s"
result= cur.execute(sql,(eng,))
self.db.commit()
cur.close()
self.disconnect()
return result'데이터 분석' 카테고리의 다른 글
| Python과 MySQL을 연동해서 회원 관리 기능 구현해보기 (0) | 2026.06.09 |
|---|