Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does deepcopy fail when copying a complex object

How can I replicate a complex object so that I can add new members to it? When I try to use deepcopy, it fails with "TypeError: cannot serialize ..."

The original problem is that I want to add some member variables to an existing object but can't because doing so results in "AttributeError: Object is fixed"

So the idea is create a full copy of the original object in a new class with the added members.

orig_obj = SomeSqlObject.get_root() # contents unclear, complex

class orig_expanded():
    def __init__(self, replicable_object):
        self.__dict__ = copy.deepcopy(replicable_object.__dict__)

        self.added_member1 = None
        self.added_list    = []

expanded_thing = orig_expanded(orig_obj)

But I get:

TypeError: cannot serialize '_io.TextIOWrapper' object

Followup answer to comment, "What is SomeSqlObject?" Perhaps my name is wrong... actual name obfuscated for the company. It is a method that returns an object that represents the base of a tree (of some kind) That tree is defined

class SomeSqlObject(ParentRegisterSet):
    """
    Implements the functionality of the Device "root" Register Set.

    """
    def __init__(self, db, v1, dg, ui):
        self.__db__ = db
        self.__dg__ = dg
        self.__ui__ = ui
        SomeSqlObject.__init__(self, v1, None)

        # note:  this class is now locked
like image 351
Andrew Ward Avatar asked Sep 15 '15 18:09

Andrew Ward


1 Answers

copy.deepcopy's behavior for classes that don't provide direct support (by defining __deepcopy__) is to pickle then unpickle the object to ensure a new instance is created. io.TextIOWrapper (which is a wrapper than converts binary file-like objects to text file-like objects) can't be serialized (because it assumes it may have external/run time state, e.g. a file descriptor that has a specific position in a file that may not be available when it's later deserialized).

The error comes because the object you're copying contains io.TextIOWrapper, and the serialization fails.

If the shared state is okay, you might limit yourself to a shallow copy, or use a composition based wrapper (based on __getattr__) to access the underlying object through the wrapper object semi-seamlessly (aside from those pesky special methods), or you might try to individually deepcopy the values from the dictionary and just ignore the ones you can't copy, e.g.:

for attr, value in vars(replicable_object).items():
    try:
        setattr(self, attr, copy.deepcopy(value))
    except Exception:
        pass
        # Alternatively, copy reference when copy impossible:
        #setattr(self, attr, value)

and just hope that the stuff you can't copy isn't too important.

like image 117
ShadowRanger Avatar answered Nov 14 '22 23:11

ShadowRanger