인프런 커뮤니티 질문&답변

코해님의 프로필 이미지

작성한 질문수

파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트

JSON 직렬화

DjangoJSONEncoder에서 언급하신 재귀적 로직의 개념

해결된 질문

작성

·

252

·

수정됨

0

class MyJSONEncoder(DjangoJSONEncoder):
    def default(self, obj):
        if isinstance(obj, QuerySet):
            return tuple(obj)
        elif isinstance(obj, Post):
            return {'id': obj.id, 'title': obj.title, 'content': obj.content}
        elif hasattr(obj, 'as_dict'):
            return obj.as_dict()
        return super().default(obj)

JSON 직렬화 강의에서 위의 구문의 return tuple(obj) 이 실행될 경우 재귀적으로 default 메서드를 탄다고 말씀하셨는데 어떤 원리인지 이해를 하지 못했습니다.

튜플로 변환될 때 어떻게 MyJSONEncoder가 이를 인지하고 작동하는지 여쭤봅니다.

답변 1

2

이진석님의 프로필 이미지
이진석
지식공유자

안녕하세요.

MyJSONEncoder에 의해서 직렬화 과정 중에, 직렬화 대상에서 각 항목마다 default 메서드를 호출해서 직렬화를 수행합니다.

obj가 만약 QuerySet 객체로서
Post(title="제목1) 과 Post(title="제목2"), 그리고 Post(title="제목3") 를 가지고 있다면

tuple(obj)의 반환값으로서, 튜플인

(Post(title="제목1"), Post(title="제목2"), Post(title="제목3"))

을 반환하게 됩니다.

그러면, 반환값인 튜플에 대해서 다시 default 메서드가 호출되며 인자로 전달이 될 것이구요.

튜플에 대해서는 다시 default 메서드를 호출하게 될 것입니다.

image

위 코드에서 튜플은 첫번째 if, 두번째 elif, 세번째 elif 조건에 부합되지 않고 super().default(obj) 에 의해서 처리될 것이구요. 파이썬 기본 타입이니 잘 처리될 겁니다.

이제 튜플에서 가지고 있는 각 값들에 대해서 default 메서드가 각각 호출될 것입니다.

그러면 default(Post(title="제목1")) 이 호출될 것이고, elif instance(obj, Post) 조건에 부합되어 {"id": obj.id, "title": obj.title, "content": obj.content}) 를 반환하겠네요.

그리고, 두번째 Post 인스턴스와 세번째 Post 인스턴스에 대해서도 동일하게 처리할 것입니다.

이해에 도움이 되셨을 지 모르겠습니다.

살펴보시고 댓글 남겨주세요.

화이팅입니다. :-)

 

코해님의 프로필 이미지
코해
질문자

안녕하세요, 상세한 답변 너무나 감사드립니다. 다만 제가 이해도가 낮아서 인지 질문 내용이 올바로 전달되지 못하였던 것 같습니다.

제가 궁금하였던 내용은 답변에서도 언급하셨던 '반환값인 튜플에 대해서 다시 default 메서드가 호출' 되는 원리에 대해서 입니다.

만약 QuerySet 타입에 해당하여 튜플로 변환된 값이 리턴된다면 default 메서드가 종료될 텐데, 어떤 원리로 다시 default 메서드가 다시 호출되어 튜플의 각 항목에 대해 실행 될 수 있는지 여쭙고자 하였습니다.

다시 한 번 살펴봐 주시면 정말 감사하겠습니다!

이진석님의 프로필 이미지
이진석
지식공유자

제가 설명드릴 수 있는 것은 각 값에 대해서 default 메서드를 통해 변환을 수행한다는 정도 일뿐, 세부구현에 대해서는 저도 정확히 알지는 못 합니다.

세부 구현이 궁금하시다면, cpython의 Lib/json/encoders.py 파일에서 JSONEncoder 클래스의 encode 메서드와 iterencode 메서드를 살펴보시면 도움이 되실 듯 합니다.

cpython/encoder.py at 3.11 · python/cpython · GitHub

이때, 단순히 코드만 보시기보다 디버거를 통해 변환과정을 하나씩 따라가보시면 이해하시는 데에 도움이 되시지 않을까 싶습니다.

화이팅입니다. :-)

코해님의 프로필 이미지

작성한 질문수

질문하기