Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

Python 객체 직렬화(Pickle) 완벽 가이드: pickle 모듈 활용법

객체 직렬화란 무엇인가?

객체 직렬화(Object Serialization)는 객체의 상태를 바이트 스트림으로 변환하는 과정을 말합니다. 이렇게 생성된 바이트 스트림은 파일에 저장하거나 소켓 등을 통해 전송할 수 있습니다. 반대로 바이트 스트림에서 원래 객체를 복원하는 과정은 역직렬화(Deserialization)라고 부릅니다.

파이썬에서는 직렬화를 '피클링(pickling)', 역직렬화를 '언피클링(unpickling)'이라는 용어로 지칭합니다. 파이썬 표준 라이브러리의 pickle 모듈은 직렬화를 위한 dump(), dumps() 함수와 역직렬화를 위한 load(), loads() 함수를 제공합니다.

다만 pickle 모듈은 파이썬 고유의 데이터 형식을 사용하기 때문에, 파이썬이 아닌 언어로 작성된 프로그램에서는 피클된 데이터를 제대로 역직렬화하지 못할 수 있습니다. 또한 신뢰할 수 없는 출처에서 전달된 데이터를 언피클링하는 것은 보안상 안전하지 않으므로 주의해야 합니다.

pickle 프로토콜의 종류

프로토콜이란 파이썬 객체를 이진(binary) 데이터로 변환하고 다시 되돌릴 때 사용되는 규약입니다. 현재 pickle 모듈은 다음과 같이 5가지 프로토콜 버전을 정의하고 있습니다.

프로토콜 버전 0최초의 '사람이 읽을 수 있는(human-readable)' 프로토콜로, 이전 버전 파이썬과 하위 호환됩니다.
프로토콜 버전 1구형 이진 포맷으로, 이전 버전 파이썬과 호환됩니다.
프로토콜 버전 2파이썬 2.3에서 도입되었으며, 신규 스타일(new-style) 클래스의 효율적인 피클링을 지원합니다.
프로토콜 버전 3파이썬 3.0에 추가되었습니다. 다른 파이썬 3 버전과의 호환성이 필요한 경우 권장됩니다.
프로토콜 버전 4파이썬 3.4에 추가되었으며, 매우 큰 객체에 대한 지원이 강화되었습니다.

설치된 파이썬 환경에서 사용 가능한 최고 프로토콜 버전과 기본 프로토콜 버전은 pickle 모듈에 정의된 상수를 통해 확인할 수 있습니다.

>>> import pickle
>>> pickle.HIGHEST_PROTOCOL
4
>>> pickle.DEFAULT_PROTOCOL
3

파일 기반 직렬화: dump()와 load()

pickle 모듈의 dump() 함수는 피클링된 객체를 파일에 쓰고, load() 함수는 파일에서 데이터를 읽어 파이썬 객체로 복원합니다.

다음 프로그램은 딕셔너리 객체를 이진 파일로 피클링하는 예제입니다.

import pickle
f = open("data.txt","wb")
dct = {"name":"Ravi", "age":23, "Gender":"M","marks":75}
pickle.dump(dct,f)
f.close()

위 코드가 실행되면 딕셔너리 객체의 바이트 표현이 data.txt 파일에 저장됩니다.

이진 파일에서 데이터를 읽어 원래 딕셔너리로 역직렬화(언피클링)하려면 아래 프로그램을 실행합니다.

import pickle
f = open("data.txt","rb")
d = pickle.load(f)
print (d)
f.close()

파이썬 콘솔에는 파일에서 읽어온 딕셔너리 객체가 출력됩니다.

{'age': 23, 'Gender': 'M', 'name': 'Ravi', 'marks': 75}

문자열 직렬화: dumps()와 loads()

pickle 모듈에는 피클링된 데이터를 문자열(bytes) 형태로 반환하는 dumps() 함수도 포함되어 있습니다. 파일을 거치지 않고 메모리상에서 직접 직렬화할 때 유용합니다.

>>> from pickle import dumps
>>> dct = {"name":"Ravi", "age":23, "Gender":"M","marks":75}
>>> dctstring = dumps(dct)
>>> dctstring
b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x04\x00\x00\x00Raviq\x02X\x03\x00\x00\x00ageq\x03K\x17X\x06\x00\x00\x00Genderq\x04X\x01\x00\x00\x00Mq\x05X\x05\x00\x00\x00marksq\x06KKu.'

loads() 함수를 사용하면 이 문자열을 언피클링하여 원래의 딕셔너리 객체를 얻을 수 있습니다.

>>> from pickle import loads
>>> dct = loads(dctstring)
>>> dct
{'name': 'Ravi', 'age': 23, 'Gender': 'M', 'marks': 75}

Pickler와 Unpickler 클래스

pickle 모듈은 Pickler 클래스와 Unpickler 클래스도 제공합니다. Pickler 클래스는 피클 데이터를 파일에 기록하고, Unpickler 클래스는 파일에서 이진 데이터를 읽어 파이썬 객체를 생성합니다.

파이썬 객체의 피클 데이터를 파일에 쓰려면 다음과 같이 작성합니다.

from pickle import Pickler
f = open("data.txt","wb")
dct = {'name': 'Ravi', 'age': 23, 'Gender': 'M', 'marks': 75}
Pickler(f).dump(dct)
f.close()

이진 파일을 언피클링하여 데이터를 다시 읽으려면 다음 코드를 사용합니다.

from pickle import Unpickler
f = open("data.txt","rb")
dct = Unpickler(f).load()
print (dct)
f.close()

사용자 정의 클래스 객체의 직렬화

파이썬 표준 자료형의 모든 객체는 피클링이 가능합니다. 나아가 사용자가 정의한 커스텀 클래스의 객체 역시 피클링과 언피클링이 가능합니다.

from pickle import *
class person:
  def __init__(self):
    self.name = "XYZ"
    self.age = 22
  def show(self):
    print ("name:", self.name, "age:", self.age)

p1 = person()
f = open("data.txt","wb")
dump(p1,f)
f.close()
print ("unpickled")
f = open("data.txt","rb")
p1 = load(f)
p1.show()

마치며

이처럼 pickle 모듈은 함수 방식과 클래스 방식 두 가지 접근으로 객체 직렬화를 지원합니다. 참고로 파이썬 표준 라이브러리에는 파이썬 객체의 내부 직렬화에 사용되는 marshal 모듈도 함께 제공되므로, 용도에 맞게 선택하여 활용하면 됩니다.