Python 기본 - 11. 파이썬으로 주소록 만들기

주소록 프로젝트 with Python

클래스를 이해하는 데에 가장 직관적인 방법으로는 역시 간단한 예제를 구현해 보는게 아니겠는가.

주소록 프로젝트, 우리 스마트폰을 보면 이름, 전화번호, 이메일 등을 저장하고 관리할 수 있는 주소록 프로그램이 있는데, 파이썬을 이용해서 기본적인 로직을 구현해 보자.

기본 클래스 만들기

가장 먼저, Contact라는 클래스를 만드는 것 부터 시작한다.

1
2
3
4
5
6
7
8
9
10
11
12
class Contact:
def __init__(self, name, phone_number, e_mail, address):
self.name = name
self.phone_number = phone_number
self.e_mail = e_mail
self.address = address

def print_info(self):
print("Name : ", self.name)
print("Phone number : ", self.phone_number)
print("E-mail : ", self.e_mail)
print("Address : ", self.address)

__init__을 사용해서 name, phone_number, e_mail, 그리고 address라는 4가지 입력값을 클래스 인스턴스를 생성할 때 받도록 하였다.

또한, 입력받은 정보를 화면에 출력하기 위해 print_info라는 메써드도 정의하였다.

그리고 run()을 작성함으로써 제대로 코드가 작동함을 확인한다.

1
2
3
4
5
6
7
8
9
10
11
12
def run():
kim = Contact('김정욱', '010-1234-5678', 'captainfox@kaist.ac.kr', 'Daejeon')
kim.print_info()

if __name__ == "__main__"
run()

>>>
Name : 김정욱
Phone number : 010-1234-5678
E-mail : captainfox@kaist.ac.kr
Address : Daejeon

데이터 입력 함수 만들기

이제, 사용자로부터 데이터를 입력받도록 함수인 set_contact()을 정의해 보자.

1
2
3
4
5
6
7
def set_contact():
name = input("Name : ")
phone_number = input("Phone number : ")
e_mail = input("E-mail : ")
address = input("Address : ")
contact = Contact(name, phone_number, e_mail, address)
return contact

사용자에게 이름, 전화번호, 이메일, 주소를 입력 받도록 하였으며, 이를 사용하여 contact라는 객체를 생성한 후 반환하도록 하였다.

run()을 수정하여 결과물을 확인한다.

1
2
3
4
5
6
7
8
9
def run():
set_contact()
print(contact)

if __name__ == "__main__"
run()

>>>
김정욱 010-1234-5678 captainfox@kaist.ac.kr Daejeon #input values

연락처 입력 메뉴 만들기

이제, 주소록 프로그램의 메뉴를 만들어 보자.

크게 [연락처 입력], [연락처 출력], [연락처 삭제], [종료] 버튼으로 구성하려 한다.

1
2
3
4
5
6
7
def print_menu():
print("1. 연락처 입력")
print("2. 연락처 출력")
print("3. 연락처 삭제")
print("4. 종료")
menu = input("메뉴선택 : ")
return int(menu)

한번 실행된 프로그램은 [종료] 버튼을 누르기 전에는 계속 실행되어야 한다. 파이썬에서는 while 1이라는 구문을 사용하면 무한 루프를 사용할 수 있다.

run()을 수정하여 4를 눌렀을 때 프로그램이 종료되도록 해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def run():
while 1:
menu = print_menu()
if menu == 4:
break

>>>
1. 연락처 입력
2. 연락처 출력
3. 연락처 삭제
4. 종료
>>>
4
>>>

이제, 앞서 작성했던 set_contact()을 1을 눌렀을 때 작동하도록 run()을 수정해 보자.

1
2
3
4
5
6
7
8
9
def run():
contact_list = [] # 빈 리스트 생성
while 1:
menu = print_menu()
if menu == 1:
contact = set_contact()
contact_list.append(contact)
elif menu == 4:
break

이제 이 프로그램은 1을 눌렀을 때 contact라는 객체를 생성하고, 이는 contact_list라는 리스트 자료형에 append()를 통해 차곡차곡 쌓일 것이다.

연락처 출력 메뉴 만들기

2를 눌렀을 때 입력받은 연락처를 출력하도록 run()을 수정해 보자.

1
2
3
4
5
6
7
8
9
10
11
def run():
contact_list = []
while 1:
menu = print_menu()
if menu == 1:
contact = set_contact()
contact_list.append(contact)
elif menu == 2:
print_contact(contact_list)
elif menu == 4:
break

이는 간단하게 print_contact()을 추가함으로써 이루어진다.

연락처 삭제 메뉴 만들기

이번에는 3을 눌렀을 때 연락처를 삭제하도록 해보자.

contact_list에서 name을 입력받았을 때, 해당하는 객체를 삭제하도록 하는 delete_contact()을 먼저 만들어 본다.

1
2
3
4
def delete_contact(contact_list, name):
for i, contact in enumerate(contact_list):
if contact.name == name:
del contact_list[i]

enumerate()함수가 쓰임에 주목하자. (사실 아직 이 함수의 동작 원리가 헷갈린다..ㅠㅠ)

이제 run()을 수정하면 되겠다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def run():
contact_list = []
while 1:
menu = print_menu()
if menu == 1:
contact = set_contact()
contact_list.append(contact)
elif menu == 2:
print_contact(contact_list)
elif menu == 3:
name = input("Name: ")
delete_contact(contact_list, name)
elif menu == 4:
break

전반적인 구조와 기능은 작성이 완료되었다. 이제 프로그램의 편의를 위해 기능을 추가해 보자.

프로그램을 켜서 연락처를 등록하였는데, 종료 후 연락처가 지워진다면 곤란할 것이다.

이 문제를 해결하려면, 연락처를 등록 후 이를 저장해야 하고, 프로그램이 동작할 때 다시 불러와야 한다.

기타 기능 추가하기

먼저 연락처 저장 기능을 담은 store_contact()부터 작성해 보자.

1
2
3
4
5
6
7
8
def store_contact(contact_list):
f = open("contact_db.txt", "wt")
for contact in contact_list:
f.write(contact.name + '\n')
f.write(contact.phone_number + '\n')
f.write(contact.e_mail + '\n')
f.write(contact.addr + '\n')
f.close()

store_contact()을 실행하면, contact_db.txt라는 텍스트 파일 안에 이름, 전화번호, 이메일, 그리고 주소가 저장된다.

이번에는 텍스트 파일로부터 정보를 로드하는 함수 load_contact()을 작성해 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def load_contact(contact_list):
f = open("contact_db.txt", "rt")
lines = f.readlines()
num = len(lines) / 4
num = int(num)

for i in range(num):
name = lines[4*i].rstrip('\n')
phone_number = lines[4*i+1].rstrip('\n')
e_mail = lines[4*i+2].rstrip('\n')
address = lines[4*i+3].rstrip('\n')
contact = Contact(name, phone_number, e_mail, address)
contact_list.append(contact)
f.close()

readlines() 함수는 파일의 모든 라인을 읽어서 각각의 줄을 요소로 갖는 리스트로 반환한다. 자세한 내용은 여기를 참고하자.

각각의 contact당 4줄의 데이터가 존재하므로 4로 나눈 후 int로 반환하게 함으로써 몇 개의 연락처가 존재하는지 확인한다.

그리고 for문을 통해 쭉 읽은 데이터들을 쪼개어서 각각의 변수에 할당하는데 끝의 공백을 제거하기 위해 .rstrip()함수를 사용하였다.

위 함수의 자세한 쓰임새는 여기를 참고하자.

마지막으로, 작성한 store_contact()load_contact()run()에 적용시킨다.

store_contact()은 프로그램을 종료하기 직전, load_contact()은 프로그램을 실행시킨 직후 수행되면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def run():
contact_list = []
load_contact(contact_list)
while 1:
menu = print_menu()
if menu == 1:
contact = set_contact()
contact_list.append(contact)
elif menu == 2:
print_contact(contact_list)
elif menu == 3:
name = input("Name: ")
delete_contact(contact_list, name)
elif menu == 4:
store_contact(contact_list)
break

최종 코드

아래는 지금까지 작성한 주소록 프로젝트의 최종 코드이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
class Contact:
def __init__(self, name, phone_number, e_mail, address):
self.name = name
self.phone_number = phone_number
self.e_mail = e_mail
self.address = address

def print_info(self):
print("Name : ", self.name)
print("Phone number : ", self.phone_number)
print("E-mail : ", self.e_mail)
print("Address : ", self.address)

def set_contact():
name = input("Name : ")
phone_number = input("Phone number : ")
e_mail = input("E-mail : ")
address = input("Address : ")
contact = Contact(name, phone_number, e_mail, address)
return contact

def print_menu():
print("1. 연락처 입력")
print("2. 연락처 출력")
print("3. 연락처 삭제")
print("4. 종료")
menu = input("메뉴선택 : ")
return int(menu)

def print_contact(contact_list):
for contact in contact_list:
contact.print_info()

def delete_contact(contact_list, name):
for i, contact in enumerate(contact_list):
if contact.name == name:
del contact_list[i]

def store_contact(contact_list):
f = open("contact_db.txt", "wt")
for contact in contact_list:
f.write(contact.name + '\n')
f.write(contact.phone_number + '\n')
f.write(contact.e_mail + '\n')
f.write(contact.address + '\n')
f.close()

def load_contact(contact_list):
f = open("contact_db.txt", "rt")
lines = f.readlines()
num = len(lines) / 4
num = int(num)

for i in range(num):
name = lines[4*i].rstrip('\n')
phone_number = lines[4*i+1].rstrip('\n')
e_mail = lines[4*i+2].rstrip('\n')
address = lines[4*i+3].rstrip('\n')
contact = Contact(name, phone_number, e_mail, address)
contact_list.append(contact)
f.close()

def run():
contact_list = []
load_contact(contact_list)
while 1:
menu = print_menu()
if menu == 1:
contact = set_contact()
contact_list.append(contact)
elif menu == 2:
print_contact(contact_list)
elif menu == 3:
name = input("Name : ")
delete_contact(contact_list, name)
elif menu == 4:
store_contact(contact_list)
break

if __name__ == "__main__":
run()

지금까지 파이썬에서 자주 사용하는 부분들만 쭉 짚어보고, 기본적인 문법에 대해서 포스팅하였다.

따로 작성하지는 않았지만, 조건문 사용이나 반복문 등은 위의 예제 같은 코드를 따라 적으면서 자연스럽게 익힐 수 있다. 다른 언어를 조금이라도 접해본 사람은 다 알꺼고..

물론 여기서 다룬 것이 파이썬의 모든 문법은 절대 아니다. 클래스 다룰때 정적메소드 (@classmethod) 같은 것도 자주 쓰긴 하는데.. 이정도만 적을 줄 알아도 기본적인 뼈대는 다 익힌거라 다른 사람이 쓴 코드 보고 그때그때 익혀 나가기를 권한다.

끗!

(참고 자료 : https://wikidocs.net/3523)