开发者

Using Python "json" module to make a class serializable

开发者 https://www.devze.com 2023-03-28 18:39 出处:网络
I am working in Python with an Email() class that I would like to extend into a SerializeEmail() class, which simply adds two further methods, .write_email() and .read_email(). I would like this sort

I am working in Python with an Email() class that I would like to extend into a SerializeEmail() class, which simply adds two further methods, .write_email() and .read_email(). I would like this sort of behaviour:

# define email
my_email = SerializeEmail()
my_email.recipients = 'link@hyrule.com'
my_email.subject = 'RE: Master sword'
my_email.body = "Master using it and you can have this."
# write email to file system for hand inspection
my_email.write_email('my_email.txt')
...
# Another script reads in email
my_verified_email = SerializeEmail()
my_verified_email.read_email('my_email.txt')
my_verified_email.send()

I have navigated the json encode/decode process, and I can successfully write my SerializeEmail() object, and read it in, however, I can't find a satisfactory way to recreate my object via a SerializeEmail.read_email() call.

class SerializeEmail(Email):

    def write_email(self,file_name):

        with open(file_name,"w") as f:
            json.dump(self,f,cls=SerializeEmailJSONEncoder,sort_keys=True,indent=4)

    def read_email(self,file_name):

        with open(file_name,"r") as f:
           json.load(f,cls=SerializeEmailJSONDecoder)

The problem here is that the json.load() call in my read_email() method returns an instance of my SerializeEmail object, but doesn't assign that object to the current instance that I'm using to call it. So righ开发者_如何学Got now I'd have to do something like this,

another_email = my_verified_email.read_email('my_email.txt')

when what I want is for the call to my_veridied_email.read_email() to populate the current instance of my_verified_email with the data on the file. I've tried

self = json.load(f,cls=SerializeEmailJSONDecoder)

but that doesn't work. I could just assign each individual element of my returned object to my "self" object, but that seems ad-hoc and inelegant, and I'm looking for the "right way" to do this, if it exists. Any suggestions? If you think that my whole approach is flawed and recommend a different way of accomplishing this task, please sketch it out for me.


While you could jump through a number of hoops to load serialized content into an existing instance, I wouldn't recommend doing so. It's an unnecessary complication which really gains you nothing; it means that the extra step of creating a dummy instance is required every time you want to load an e-mail from JSON. I'd recommend using either a factory class or a factory method which loads the e-mail from the serialized JSON and returns it as a new instance. My personal preference would be a factory method, which you'd accomplish as follows:

class SerializeEmail(Email):

    def write_email(self,file_name):

        with open(file_name,"w") as f:
            json.dump(self,f,cls=SerializeEmailJSONEncoder,sort_keys=True,indent=4)

    @staticmethod
    def read_email(file_name):

        with open(file_name,"r") as f:
           return json.load(f,cls=SerializeEmailJSONDecoder)

# You can now create a new instance by simply doing the following:
new_email = SerializeEmail.read_email('my_email.txt')

Note the @staticmethod decorator, which allows you to call the method on the class without any implicit first argument being passed in. Normally factory methods would be @classmethods, but since you're loading the object from JSON, the implicit class argument is unnecessary.

Notice how, with this modification, you don't need to instantiate a SerializeEmail object before you can load another one from JSON. You simply call the method directly on the class and get the desired behavior.

0

精彩评论

暂无评论...
验证码 换一张
取 消