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으로 변환하여 수정할 수 있습니다.
수정 전 코드
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 이란 (출처 위키백과)
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 제공
댓글