Python 3.2 Pickle 모듈
오늘 포스트는 인제대학교 의용공학과 전공 과정인 중급실용전산 수업에서 다뤘던 Persistence 관련 모듈 중 Pickle에 관한 것이다. 컴퓨터 프로그래밍에 있어 영속화를 익히는 과정은 대체적으로 ASCII 포맷의 Text 파일 다루기, Binary 포맷의 파일 다루기, 시리얼화(serialization), 마크업(HTML, XML 등의 ASCII 또는 그 외 Binary Markup), 데이터베이스 전체를 다루거나 또는 그 일부만 언급한 책자도 많다. 위 과정에서 채택한 주교재인 Head First Programming 에선 시리얼화를 이용한 영속화 모듈인 Pickle과 Shelve를 다루지 않으므로 이를 보강하는 의도에서 이 포스트와 다음 포스트인 Python Persistence (2) : Shelve 모듈에서 이들에 대해 살펴보도록 한다.
Pickle이나 Shelve와 같은 시리얼화를 이용한 영속화 작업을 수행하는 이유는 프로그램에서 생성한 객체의 실행 시 담고 있는 그 상태 값을 그대로 컴퓨터의 저장 매체에 저장했다가 추후에 그대로 사용하기 위한 목적을 쉽게 달성하기 위해서다. C#이나 Java 등에서도 이러한 시리얼화를 지원하지만 Python은 Pickle 및 Shelve 모듈로 간단히 구현할 수 있도록 했다.
Pickle 모듈을 이용한 코드 예제는 간단한 일정관리용 콘솔 프로그램으로 하도록 한다. 우선 콘솔용 UI를 아래와 같이 작성했고, 그 출력은 다음과 같다.
1: #!/usr/bin/env python2: # -*- coding: UTF-8 -*-3:4: def clearAll():5: return []6:7: def printList(items):8: print ("-" * 30)9: print ("%d개의 일정이 등록되어 있습니다." % len(items))10: for item in items:11: print("\t%s" % item)12: print ("-" * 30)13:14: import pickle15:16: toDo = [] # 사용자가 입력한 일정 담을 리스트17: menu = ["출력", "전체 제거", "추가"] # 메뉴 리스트18: running = True19:20: print ("*" * 30)21: print ("일정관리")22: print ("*" * 30)23:24: while running:25: option = 126:27: for m in menu:28: print ("%d. %s" % (option, m))29: option += 130: print ("%d. %s" % (option, "종료"))31: try:32: command = int(input("원하는 메뉴 번호를 입력하세요: "))33: except ValueError:34: command = 035:36: if command == option:37: running = False38: elif command == 1:39: printList(toDo)40: elif command == 2:41: toDo = clearAll()42: elif command == 3:43: do = input("\t일정명: ")44: toDo.append(do)45: printList(toDo)
Pickle 모듈을 사용하기 위해서는 14행과 같이 모듈을 import 한다. Pickle에서는 파일을 바이너리 포맷으로 다루게 되므로 파일 읽거나 쓸 때 파일모드는 반드시 binary 포맷으로 해야 한다. 즉 open() 내장 함수의 모드 파라메터를 ‘rb’와 ‘wb’로 해야 한다. 우선 파일을 저장하는 save() 함수를 다음과 같이 작성했다. Pickle 모듈의 파일 저장 함수는 dump() 이다. 오류처리 구문을 제외하면 이 함수는 with 문을 통해 파일 처리를 Python의 Context Manager에 위임하고, 저장할 객체(이 예제에서는 list object)와 파일 핸들러를 pickle.dump() 함수에 파라메터로 넘겨주는 것이 다이다.
1: def save(items, fname="items.todo"):2: """3: save todo items into binary file4: """5: try:6: with open(fname, "wb") as fh:7: pickle.dump(items, fh)8: except IOError as ioerr:9: print ("File Error: %s" % str(ioerr))10: except pickle.PickleError as pklerr:11: print ("Pickle Error: %s" % str(pklerr))
위 save() 함수를 첫 코드에 작성 후, 첫 코드의 46번째 줄에 save(toDo)를 추가하면 프로그램 실행 시 파일이 생성된다. 여기서 save(toDo) 코드는 while 문이 종료되는 시점에 호출되도록 들여쓰기(indentation)을 주의해야 한다. 코드 일부와 그 실행 시 예는 아래와 같으며, 생성된 파일(items.todo)에 저장된 내용도 그 아래 표시했다.
23: ...24: while running:25: ...45: printList(toDo)46: save(toDo)
이제 프로그램 실행 시 Pickle 모듈로 저장한 파일이 있다면 이를 읽어 들여 되돌려 주는 load() 함수를 추가한다. 기존에 생성된 파일이 없으면 save() 함수에 빈 리스트 하나를 파라메터로 넘겨 비어있는 파일 하나를 만들도록 했다. 그 코드는 아래와 같다. 오류처리 구문을 제외하면, save() 함수와 마찬가지로 파일 핸들러를 얻고 이를 pickle.load() 함수에 파라메터로 넘겨 파일을 읽어 들이면 된다.
1: def load(fname="items.todo"):2: """3: load todo items binary file into memory4: and assigns its values to corresponding object's states5: """6: savedItems = [] # 빈 리스트 생성7: try:8: with open(fname, "rb") as fh:9: savedItems = pickle.load(fh)10: except IOError as ioerr:11: save(savedItems, fname) # create empty file12: except pickle.PickleError as pklerr:13: print ("Pickle Error: %s" % str(pklerr))14: finally:15: return savedItems
이 프로그램의 메인 부분에 해당하는 첫 코드의 16행 toDo = [] 코드를 아래와 같이 수정 후 프로그램을 실행 후, 출력 메뉴를 선택하면 그 아래 그림에 나타낸 것과 같이 앞서 save() 함수 적용 후 입력한 내용이 출력되는 것을 확인 할 수 있다.
...16: toDo = load() # 사용자가 입력한 일정 담을 리스트...
이 포스트에서는 Python에서 Pickle 모듈을 이용한 영속화 예제를 살펴봤다. 이 예제의 경우 단일한 일정목록을 그 개수에 제한 없이 사용할 수 있지만 날짜와 같은 구분 지을 수 있는 키로 여러 데이터 세트를 상황에 맞게 사용하려면 리스트 대신 딕셔너리 객체를 이용하면 되지만 시리얼화로 저장한 파일 내용 전체를 읽어 들여야 해서 비효율 적이다. 필요한 부분만 별도로 관리할 수 있는 모듈이 포스트 처음에 언급한 Shelve 모듈이다. 이는 다음 포스트에서 살펴보도록 한다. 이 프로그램의 전체 코드는 아래와 같다.
1: #!/usr/bin/env python2: # -*- coding: UTF-8 -*-3: #-------------------------------------------------------------------------------4: # Name: TodoListPickle5: # Purpose: Pickle 모듈을 이용한 파일 영속화(persistence) 예제6: #7: # Author: oscarpark8: #9: # Created: 18-11-201110: # Copyright: (c) oscarpark 201111: # Licence: Licence Free12: #-------------------------------------------------------------------------------13:14:15: def clearAll():16: return []17:18: def printList(items):19: print ("-" * 30)20: print ("%d개의 일정이 등록되어 있습니다." % len(items))21: for item in items:22: print("\t%s" % item)23: print ("-" * 30)24:25: def save(items, fname="items.todo"):26: """27: save todo items into binary file28: """29: try:30: with open(fname, "wb") as fh:31: pickle.dump(items, fh)32: except IOError as ioerr:33: print ("File Error: %s" % str(ioerr))34: except pickle.PickleError as pklerr:35: print ("Pickle Error: %s" % str(pklerr))36:37: def load(fname="items.todo"):38: """39: load todo items binary file into memory40: and assigns its values to corresponding object's states41: """42: savedItems = [] # 빈 리스트 생성43: try:44: with open(fname, "rb") as fh:45: savedItems = pickle.load(fh)46: except IOError as ioerr:47: save(savedItems, fname) # create empty file48: except pickle.PickleError as pklerr:49: print ("Pickle Error: %s" % str(pklerr))50: finally:51: return savedItems52:53: import pickle54:55: toDo = load() # 사용자가 입력한 일정 담을 리스트56: menu = ["출력", "전체 제거", "추가"] # 메뉴 리스트57: running = True58:59: print ("*" * 30)60: print ("일정관리")61: print ("*" * 30)62:63: while running:64: option = 165:66: for m in menu:67: print ("%d. %s" % (option, m))68: option += 169: print ("%d. %s" % (option, "종료"))70: try:71: command = int(input("원하는 메뉴 번호를 입력하세요: "))72: except ValueError:73: command = 074:75: if command == option:76: running = False77: elif command == 1:78: printList(toDo)79: elif command == 2:80: toDo = clearAll()81: save(toDo)82: elif command == 3:83: do = input("\t일정명: ")84: toDo.append(do)85: printList(toDo)86: save(toDo)
댓글 없음:
댓글 쓰기