How to copy a class instance in python?

前端 未结 3 1522
遥遥无期
遥遥无期 2021-02-07 03:16

I would like to make a copy of a class instance in python. I tried copy.deepcopy but I get the error message:

RuntimeError: Only Variables cr

3条回答
  •  暗喜
    暗喜 (楼主)
    2021-02-07 03:59

    I have mostly figured it out. The only problem which I cannot overcome is knowing an acceptable set of initialization arguments (arguments for __init__) for all classes. So I have to make the following two assumtions:

    1) I have a set of default arguments for class C which I call argsC. 2) All objects in C can be initialized with empty arguments.

    In which case I can First: Initialize a new instance of the class C from it's instance which I want to copy c:

    c_copy = c.__class__(**argsC)
    

    Second: Go through all the attributes of c and set the attributes c_copy to be a copy of the attributes of c

    for att in c.__dict__:
        setattr(c_copy, att, object_copy(getattr(c,att)))
    

    where object_copy is a recursive application of the function we are building.

    Last: Delete all attributes in c_copy but not in c:

    for att in c_copy.__dict__:
        if not hasattr(c, att):
            delattr(c_copy, att)
    

    Putting this all together we have:

    import copy
    
    def object_copy(instance, init_args=None):
        if init_args:
            new_obj = instance.__class__(**init_args)
        else:
            new_obj = instance.__class__()
        if hasattr(instance, '__dict__'):
            for k in instance.__dict__ :
                try:
                    attr_copy = copy.deepcopy(getattr(instance, k))
                except Exception as e:
                    attr_copy = object_copy(getattr(instance, k))
                setattr(new_obj, k, attr_copy)
    
            new_attrs = list(new_obj.__dict__.keys())
            for k in new_attrs:
                if not hasattr(instance, k):
                    delattr(new_obj, k)
            return new_obj
        else:
            return instance
    

    So putting it all together we have:

    argsC = {'a':1, 'b':1}
    c = C(4,5,r=[[1],2,3])
    c.a = 11
    del c.b
    c_copy = object_copy(c, argsC)
    c.__dict__
    

    {'a': 11, 'r': [[1], 2, 3]}

    c_copy.__dict__
    

    {'a': 11, 'r': [[1], 2, 3]}

    c.__dict__
    

    {'a': 11, 'r': [[1, 33], 2, 3]}

    c_copy.__dict__
    

    {'a': 11, 'r': [[1], 2, 3]}

    Which is the desired outcome. It uses deepcopy if it can, but for the cases where it would raise an exception, it can do without.

提交回复
热议问题