'Encoding and Decoding Class Objects between Python and JSON

I'm encoding and decoding inherited classes between Python 2.7 and a JSON file. This works, but I'm concerned that as I add types, I will need to keep expanding the encoder and decoder to check every type. Is there a more automatic way to convert the class to JSON and back again? It doesn't necessarily need to be an enum.

More specifically, I'm trying to encode and decode a list of equipment objects which all inherit from the Equipment class. Right now, I'm encoding by looking at the isinstance variable, and if it matches one of the subclasses (Transformer, GeneralEquipment, or Motor), I'm adding an extra enum key to the JSON for the equipment type. Then when I decode, the same check happens in reverse. But this means expanding that check for every sub-class I create, and there may be 10-20 equipment types when I'm done.

import json
import math
from enum import Enum

class EquipType(str, Enum):
    GeneralEquipment = 'GENERAL_EQUIPMENT'
    Transformer = 'TRANSFORMER'
    Motor = 'MOTOR'

class Equipment:

    VA = None

    def __init__(self, tag='', volts=0, phases=1, fla=0):
        self.tag = tag
        self.volts = volts
        self.phases = phases
        self.fla = fla

    def volt_amps(self):
        if self.phases == 3:
            self.VA = self.volts*self.fla*math.sqrt(3)
        else:
            self.VA = self.volts*self.fla

    def wire_size(self):
        print "calculated as if this were equipment."

class GeneralEquipment(Equipment):
    def wire_size(self):
        print "calculated as if this were general equipment."

class Transformer(Equipment):
    def wire_size(self):
        print "calculated as if this were a transformer."

class Motor(Equipment):
    def wire_size(self):
        print "calculated as if this were a motor."

class EquipmentEncoder(json.JSONEncoder):
    def default(self, z):
        if isinstance(z, GeneralEquipment):
            return {"equiptype" : EquipType.GeneralEquipment, "tag" : z.tag, "volts" : z.volts, "phases" : z.phases, "fla" : z.fla}
        elif isinstance(z, Transformer):
            return {"equiptype" : EquipType.Transformer, "tag" : z.tag, "volts" : z.volts, "phases" : z.phases, "fla" : z.fla}
        elif isinstance(z, Motor):
            return {"equiptype" : EquipType.Motor, "tag" : z.tag, "volts" : z.volts, "phases" : z.phases, "fla" : z.fla}
        else:
            return super().default(z)

def EquipmentDecoder(dct):
    if dct['equiptype'] == EquipType.GeneralEquipment:
        return Equipment(dct['tag'],dct['volts'],dct['phases'],dct['fla'])
    elif dct['equiptype'] == EquipType.Transformer:
        return Transformer(dct['tag'],dct['volts'],dct['phases'],dct['fla'])
    elif dct['equiptype'] == EquipType.Motor:
        return Motor(dct['tag'],dct['volts'],dct['phases'],dct['fla'])

MyEquipList = [GeneralEquipment('EF-1 (Bathroom fan)',120,1,5),Transformer('XMFR-2',208,3,5),Motor('EF-23',480,3,24)]

print(MyEquipList)
print(MyEquipList[0].tag)

file_path = 'C:\\data2.json'
with open(file_path, 'w') as dataFile:
    json.dump(MyEquipList, dataFile, cls = EquipmentEncoder)
print ("data dumped")

with open(file_path, 'r') as dataFile:
    MyEquipList =  json.load(dataFile,object_hook = EquipmentDecoder)
print ("data loaded")

print(MyEquipList[0].tag)

for e in 

MyEquipList
===========

:
    e.volt_amps()
    e.wire_size()
    print (e.tag, e.VA)


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source