본문 바로가기
SW 개발/Python

Python JSON 사용 시 TypeError: Object of type bytes is not JSON serializable

by Kibua20 2020. 6. 29.

Python 3.8 버전에서  Dictionary 데이터를 JSON변환 시 발생했던 TypeError: Object of type bytes is not JSON serializable 에러에 대한 수정 사항입니다. 

 

json.dumps()함수는 일반 obj를 JSON 포맷의 string으로 serialize 한다고 설명되어 있다(아래 그림) . 즉,  Dictionary를 JSON으로 변환하기 위해서는 일반적으로 string으로 직렬화하여 전달해야 하지만, 직렬화가 정의되지 않은 byte array 로 전달하여 Type error 에러가 발생하는 것입니다.  decode('utf8') 함수를 사용해서 byte array를  string으로 변환하여 수정할 수 있습니다. 

 

JSON.dumps() 함수 설명


수정 전 코드 

def CreateMessage(sender, to, subject, message_text):

   message = MIMEText(message_text, 'html')

   message['to'] = to

   payload= {'raw': base64.urlsafe_b64encode(message.as_bytes())}

  #json으로 변환 시 Type error 발생 

    json.dumps(payload) 


수정 후 코드 

def CreateMessage(sender, to, subject, message_text):

   message = MIMEText(message_text, 'html')

   message['to'] = to

 

   #dictionary 중  urlsafe_b64encode()의 return 값을 다시 string으로 변환

   payload= {'raw': base64.urlsafe_b64encode(message.as_bytes()).decode('utf8')}  

    #json으로 변환 

    json.dumps(payload)


에러 메시지 분석:

Traceback (most recent call last):
File "./mail_sender.py", line 141, in sendmail print (json.dumps(payload))
File "python3.8/json/__init__.py", line 231, in dumps return _default_encoder.encode(obj)
File "python3.8/json/encoder.py", line 199, in encode chunks = self.iterencode(o, _one_shot=True)
File "python3.8/json/encoder.py", line 257, in iterencode return _iterencode(o, 0)
File "python3.8/json/encoder.py", line 179, in default
raise TypeError(f'Object of type {o.__class__.__name__}    ' TypeError: Object of type bytes is not JSON serializable

 

에러 메시지는 dictionary 타입의 payload가 byte array를 포함하고 있어, 이를 JSON으로 변환(=직렬화, serialize)하는 과정에서 Type error가 발생한 것이다. base64.urlsafe_b64encode(message.as_bytes()의 return 값은 byte array이고,  JSON 변환을 위해서는 string 으로 변환해야 한다. 

 

수정 전 print (payload) 결과 값:  Byte array로 return 함 b'DVJWld....' 로 표시함 

      {'raw': b'DVJWld4c2J5QjN'}

 

수정 후 print (payload): byte arrage를 decode('utf8')함수를 이용해서 string으로 return 한다. 한글과 같은 유니코드인 경우를 대비해서 utf8 로 encoding type을 지정한다. (byte b 표시가 없어짐)

 

     {'raw': 'DVJWld4c2J5QjN'}

 

수정 확인:  JSON을 확인하면 아래와 같이 정상적으로 표시된다. 

     print (json.dumps(payload)): 

     {"raw": "DVJWld4c2J5QjN"}

 

※ [참고] Byte array는 string으로 쉽게 변환이 가능하지만, 복잡한 class 인 경우에는  json.dump() 호출 시 사용자 정의 직렬화 함수인 default handler를 지정해서 encoding을 확장할 수 있다. 자세한 내용은 아래 블로그와 Python manual을 확인 바란다.

 

JSON.dump()에서 default handler를 추가해도 해결이 가능하다. (출처: https://dgkim5360.tistory.com/entry/not-JSON-serializable-error-on-python-json)

 

 

default 함수 설명:출처: https://docs.python.org/ko/3/library/json.html

※ JSON 이란 (출처 위키백과)

JSON(JavaScript Object Notation)은 속성-값 쌍( attribute–value pairs and array data types (or any other serializable value)) 또는 "키-값 쌍"으로 이루어진 데이터 오브젝트를 전달하기 위해 인간이 읽을 수 있는 텍스트를 사용하는 개방형 표준 포맷이다. 비동기 브라우저/서버 통신 (AJAX)을 위해, 넓게는 XML(AJAX가 사용)을 대체하는 주요 데이터 포맷이다. 특히, 인터넷에서 자료를 주고 받을 때 그 자료를 표현하는 방법으로 알려져 있다. 자료의 종류에 큰 제한은 없으며, 특히 컴퓨터 프로그램의 변수값을 표현하는 데 적합하다. 

    - 주석 허용 안됨

    - XML 유사한 구조를 가지고 있음

   -  더블 따옴표" 만 허락함 

   - {"name2": 50, "name3": "값3", "name1": true}

 

 ※ base64.urlsafe_b64encode(s) 설명 (출처: Python Doc)

Encode bytes-like object s using the URL- and filesystem-safe alphabet, which substitutes - instead of + and _ instead of / in the standard Base64 alphabet, and return the encoded bytes. The result can still contain =.

 

<관련 글>

[모바일/Python] - Python smtplib 사용한 email 발송 예제 (gmail)

[모바일/Python] - Python SyntaxError: Non-ASCII character in file on, but no encoding declared

[모바일/Python] - Python 2.7과 3.8호환성: a bytes-like object is required, not 'str'에러 수정

[모바일/Python] - [Tips] Python: XML Parsing 시 multiple elements on top level

[모바일/Python] - [Tips] Python 에서 XML comment 처리 - Sample code 제공

[모바일/Python] - [Tips] XML 에서 예약/특수 문자 처리




댓글