Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update pickled objects when adding an attribute to a Python class

I defined a Python3 class and then used pickle to serialize and save an instance to file. Later I added another instance attribute to my class, but I realized that if I load my instance and try to reference that attribute I will get an "Object has no attribute" error since the instance was constructed without it. What are the best options for adding the new attribute to my pickled object(s) and configuring it?

In code, I defined a class like

# First definition
class Foo:
  def __init__(self, params):
    # define and initialize attributes
  def print_number(self):
    print(2)

I create and serialize an instance using pickle, and save it to file

import pickle

inst = Foo(params)
with open("filename", 'wb') as f:
  pickle.dump(inst, f)

Then I want my class to behave a bit differently, so I update its definition:

# Updated definition
class Foo:
  def __init__(self, params):
    # define and initialize attributes
    self.bar = "baz"                    # bar is a new attribute
  def print_number(self):
    print(3)                            # prints 3 instead of 2

Then I load my instance and try to call some methods

import pickle

with open("filename", 'rb') as f:
  inst = pickle.load(f)

inst.print_number()
print(inst.bar)

Since pickle doesn't save method definitions, the instance method's behaviour is updated so inst.print_number() prints 3 instead of 2. However the reference inst.bar results in an "Object has no attribute" error because inst was initialized before Foo had that attribute in its definition.

Update

This was a bit of a noob question on my part, I didn't realize that Python lets you just do something like inst.bar = "baz" and set things dynamically (I'm coming from a Java background where everything has to be fixed from the start). I am still interested in hearing about ways to do this properly and/or Pythonicaly and/or pickle-specificly, especially when multiple class updates can be expected.

like image 704
William Avatar asked Oct 26 '25 09:10

William


1 Answers

You could use class inheritance to add new methods/attributes to an existing class:

# First definition
class Foo:
    def __init__(self, params):
        self.params = params
    def print_number(self):
        print(2)

import pickle

inst = Foo('params')
with open("filename", 'wb') as f:
    pickle.dump(inst, f)

del inst

# Updated definition
class Foo(Foo):
    def __init__(self, params):
        super().__init__(params)
        self.bar = "baz"                    # bar is a new attribute
    def print_number(self):
        print(3)


with open("filename", 'rb') as f:
    inst = Foo(pickle.load(f))

inst.print_number()
print(inst.bar)

# Outputs:
# 3
# baz

Or it probably makes more sense in practice to do something like this:

with open("filename", 'rb') as f:
    inst = pickle.load(f)

# Updated definition
class Foo(inst.__class__):
    def __init__(self, params):
        super().__init__(params)
        self.bar = "baz"                    # bar is a new attribute
    def print_number(self):
        print(3)



inst = Foo(inst)
inst.print_number()
print(inst.bar)
like image 124
cosmic_inquiry Avatar answered Oct 27 '25 21:10

cosmic_inquiry



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!