Só uns detalhes sobre o código:
Em vez de verificar se o arquivo existe, simplesmente tente abri-lo e capture as exceções. Essa ideia de verificar e só depois abrir gera uma condição de corrida (race condition): em resumo, entre a verificação e a abertura, o estado do arquivo pode ter mudado e dar erro do mesmo jeito (mais detalhes aqui).
O with
já garante que o arquivo será fechado ao final, então não precisa chamar close()
.
Para verificar a extensão do arquivo e demais manipulações, dê uma olhada no módulo pathlib
- disponível desde o Python 3.4 e considerada uma alternativa mais moderna à os.path
(veja aqui um comparativo).
Por fim, se a ideia é que o arquivo JSON seja apenas para "organização" interna e não necessariamente para ser lido por humanos, considere alternativas como os módulos pickle
ou shelve
.