Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Python

파이썬 객체의 직렬화와 역직렬화: 2부

by
Difficulty:IntermediateLength:MediumLanguages:

Korean (한국어) translation by Dae-yeop Lee (you can also view the original English article)

이것은 파이썬 객체를 직렬화하고 역직렬화하는 튜토리얼의 2부입니다. 1부에서는 기초적인 내용을 배우고 피클과 JSON의 기능에 대해 배웠습니다.

2부에서는 YAML을 탐구하고(1부의 예제를 기반으로), 성능 및 보안 고려 사항에 대해 논의하고, 추가적인 직렬화 형식을 검토한 다음, 마지막으로 올바른 직렬화 방법을 선택하는 방법을 배웁니다.

YAML

YAML은 제가 가장 좋아하는 형식입니다. YAML은 인간 친화적인 데이터 직렬화 형식입니다. 피클 및 JSON과 달리 YAML은 파이썬 표준 라이브러리의 일부가 아니므로 설치할 필요가 있습니다.

pip install yaml

yaml 모듈에는 load()dump() 함수만 있습니다. 기본적으로는 두 함수는 loads()dumps()처럼 문자열을 처리하지만 열린 스트림에 해당하는 두 번째 인자를 받아 파일로(또는 파일로부터) 덤프/로드할 수 있습니다.

YAML이 피클이나 JSON과 비교해서 얼마나 가독성 높은지 눈여겨보십시오. 그리고 YAML의 가장 멋진 부분은 YAML이 파이썬 객체를 이해한다는 것입니다! 맞춤형 인코더나 디코더가 필요없습니다. 다음은 YAML을 이용해 복잡한 객체를 직렬화/역직렬화하는 예제입니다.

보다시피 YAML에는 파이썬 객체에 태그를 다는 자체적인 표기법이 있습니다. 출력 결과는 여전히 사람이 읽을 수 있습니다. datetime 객체는 특별한 태그 지정을 필요로 하지 않습니다. 왜냐하면 YAML은 datetime 객체를 기본적으로 지원하기 때문입니다.

성능

성능을 생각하기에 앞서 성능이 문제가 되는지 생각해볼 필요가 있습니다. 적은 양의 데이터를 직렬화/역직렬화하는 경우가 비교적 드물다면(예: 프로그램을 시작하는 부분에서 설정 파일 읽기) 성능이 별로 문제가 되지 않습니다.

그러나 시스템을 프로파일링해서 직렬화 및/또는 역직렬화가 성능 문제를 일으킨다는 사실을 알게 됐다고 가정한다면 다음은 이러한 성능 문제를 해결하는 방법입니다.

성능에는 두 가지 측면이 있습니다: 직렬화/역직렬화를 얼마나 빠르게 수행할 수 있고, 직렬화된 표현은 얼마나 큰가?

다양한 직렬화 형식의 성능을 테스트하기 위해 여기서는 큰 자료 구조를 만들고 피클, YAML, JSON을 이용해 직렬화/역직렬화하겠습니다. big_data 리스트에는 5,000개의 복잡한 객체가 담겨 있습니다.

피클

여기서는 실행 시간을 측정하는 편리한 %timeit 매직 함수를 사용하기 위해 IPython을 사용하겠습니다.

기본 피클은 직렬화하는 데 83.1밀리초가, 역직렬화하는 데 29.2밀리초가 걸리고, 직렬화된 크기는 747,328바이트입니다.

이번에는 가장 높은 프로토콜을 지정해 보겠습니다.

흥미로운 결과입니다. 직렬화 시간은 겨우 21.2밀리초로 줄어들었지만 역직렬화 시간은 25.2밀리초로 약간 증가했습니다. 직렬화된 크기는 394,350바이트(52%)로 상당히 줄어들었습니다.

JSON

좋습니다. 성능은 인코딩의 경우 피클보다 약간 나쁘지만 디코딩의 경우 훨씬 더 나쁩니다(6 배 느림). 무슨 일이 일어난 걸까요? 이것은 object_hook 함수의 결과로서, 이 함수는 딕셔너리를 객체로 변환해야 하는지 확인하기 위해 모든 딕셔너리에 대해 실행돼야 합니다. 객체 후크 없이 실행하는 편이 훨씬 빠릅니다.

여기서 배울 수 있는 점은 JSON을 직렬화 및 역직렬화할 경우 전체 성능에 큰 영향을 줄 수 있으므로 사용자 정의 인코딩에 세심하게 신경 써야 한다는 것입니다.

YAML

좋습니다. YAML은 아주 아주 느립니다. 그러나 한 가지 흥미로운 점은 직렬화된 크기가 단지 200,091바이트에 불과하다는 것입니다. 이는 피클과 JSON보다 훨씬 좋은 결과입니다. 이제 내부를 살짝 들여다 봅시다.

YAML은 매우 영리합니다. 총 5,000개의 dict는 'a' 키에 대해 동일한 값을 공유하므로 모든 키가 한 번만 저장되고, 모든 객체에 대해 *id001을 통해 참조합니다.

보안

보안은 종종 중요한 문제입니다. 피클과 YAML은 파이썬 객체를 생성하는 특성 때문에 코드 실행 공격에 취약합니다. 영악하게 형식화된 파일에는 피클이나 YAML에 의해 실행될 임의의 코드가 담길 수 있습니다. 하지만 불안해 할 필요는 없습니다. 이것은 의도적으로 설계된 것으로 피클의 문서에도 설명돼 있습니다.

경고: pickle 모듈은 잘못됐거나 악의적으로 생성된 데이터로부터 보호되지 않습니다. 신뢰할 수 없거나 인증되지 않은 곳에서 받은 데이터는 절대로 언피클해서는 안 됩니다.

YAML의 문서에도 다음과 같이 쓰여 있습니다.

경고: 신뢰할 수 없는 곳에서 받은 데이터로 yaml.load를 호출하는 것은 안전하지 않습니다! yaml.load는 pickle.load만큼 강력해서 어떠한 파이썬 함수도 호출할 수 있습니다.

피클이나 YAML을 이용해 신뢰할 수 없는 출처에서 받은 직렬화된 데이터를 로드하면 안 된다는 것만 이해하면 됩니다. JSON은 괜찮지만 노출될 수도 있는 사용자 정의 인코더/디코더가 있는 경우도 마찬가지입니다.

yaml 모듈에서는 yaml.safe_load()를 제공하는데, 이 함수는 단순한 객체만 로드하지만 이 경우 YAML의 위력을 많이 잃어버려서 그냥 JSON을 사용하기로 할 수도 있습니다.

기타 형식

그 밖에 사용할 수 있는 다른 여러 직렬화 형식도 많습니다. 다음은 그중 몇 가지입니다.

Protobuf

프로토콜 버퍼라고도 하는 Protobuf는 구글의 데이터 교환 형식입니다. 이것은 C++로 구현돼 있지만 파이썬 바인딩도 있습니다. 프로토콜 버퍼는 정교한 스키마를 가지고 있으며 데이터를 효율적으로 압축합니다. 매우 강력하지만 사용하기가 그다지 쉽지 않습니다.

MessagePack

MessagePack은 또 다른 인기 있는 직렬화 형식입니다. MessagePack 또한 바이너리 형식이고 효율적이지만 Protobuf와 달리 스키마가 필요하지 않습니다. JSON과 타입 체계가 비슷하지만 조금 더 풍부합니다. 어떠한 형식으로도 키를 만들 수 있으며, 문자열뿐 아니라 비UTF8 문자열도 지원합니다.

CBOR

CBOR은 Concise Binary Object Representation(간결한 바이너리 객체 표현)의 약자입니다. CBOR도 JSON 데이터 모델을 지원합니다. CBOR은 Protobuf나 MessagePack만큼 유명하지 않지만 다음과 같은 두 가지 이유에서 흥미롭습니다.

  1. 공식 인터넷 표준(RFC 7049)입니다.
  2. 사물 인터넷(IoT; Internet of Things)를 위해 특별히 고안됐습니다.

어떻게 골라야 할까요?

이것은 큰 문제입니다. 옵션이 너무 많을 경우 어떻게 선택해야 할까요? 다음과 같은 요소에 대해 고려해 봅시다.

  1. 직렬화된 형식을 사람이 읽을 수 있거나 인간이 편집할 수 있어야 합니까?
  2. 직렬화된 콘텐츠를 신뢰할 수 없는 출처에서 받아야 합니까?
  3. 직렬화/역직렬화가 성능 병목 지점입니까?
  4. 직렬화된 데이터를 비파이썬 환경과 교환해야 합니까?

여기서는 여러분이 어떤 직렬화 방법을 택해야 할지 선택하기 쉽게 만들고 몇 가지 일반적인 시나리오와 각 시나리오에 권장하는 형식을 다루겠습니다.

파이썬 프로그램의 로컬 상태 자동 저장

이 경우 피클(cPickle)에 HIGHEST_PROTOCOL을 지정해서 사용합니다. 이 방법은 빠르고 효율적이며, 특별한 코드 없이 대부분의 파이썬 객체를 저장하고 로드할 수 있습니다. 또한 로컬 영구 캐시로도 사용할 수 있습니다.

설정 파일

단연 YAML입니다. 인간이 읽거나 편집해야 하는 것에 대해 YAML보다 단순한 것은 아무것도 없습니다. YAML은 Ansible과 다른 여러 프로젝트에서 성공적으로 사용되고 있습니다. 어떤 상황에서는 설정 파일로 파이썬 모듈을 직접 사용하는 방식을 선호할지도 모릅니다. 그 방식이 맞을 수도 있겠지만 그것은 직렬화가 아니고 프로그램의 일부이며 별도의 설정 파일이 아닙니다.

웹 API

이 부문에서는 JSON이 가장 적합합니다. 오늘날 웹 API는 JSON을 기본적으로 사용하는 자바스크립트 웹 애플리케이션에서 가장 자주 사용됩니다. 일부 웹 API는 다른 형식(예: 빽빽한 표 형식의 결과 집합의 경우 csv)을 반환할 수도 있지만 최소한의 오버헤드(각 행을 모든 칼럼명이 포함된 객체로 반복할 필요 없이)로 csv 데이터를 JSON으로 패키징할 수 있을 것입니다.

대용량/저대기 대규모 통신

바이너리 프로토콜인 Protobuf(스키마가 필요한 경우)나 MessagePack, CBOR 중 하나를 사용합니다. 자체적인 테스트를 실행해 각 직렬화 방식의 성능과 대표적인 기능을 확인합니다.

결론

파이썬 객체의 직렬화와 역직렬화는 분산 시스템의 중요한 측면입니다. 네트워크상으로 직접 파이썬 객체를 전송할 수는 없습니다. 다른 언어로 구현된 다른 시스템과 상호운용해야 하는 경우도 종종 있고, 때로는 영구 저장소에 프로그램의 상태를 저장하고 싶을 때도 있습니다.

파이썬 표준 라이브러리에는 여러 가지 직렬화 체계가 포함돼 있으며, 다른 여러 모듈이 서드파티 모듈로 제공됩니다. 모든 선택지와 각각의 장단점을 알고 있으면 특정 상황에 가장 적합한 방법을 선택할 수 있을 것입니다.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.