pythonpython-3.xclassoopcloning

Cloning an object in Python


I am writing a program which involves recursively making an instance of an object that may be passed as an argument. A sample of program:

from copy import copy
class test():
    def __init__(self, sample=None):
        if not sample:
            self.a = int(input())
            self.b = int(input())
        else:
            self = copy(sample)

# MAIN HERE..
sampleobj1 = test()
print (sampleobj1.a, sampleobj1.b)
sampleobj2 = test(sampleobj1)
print (sampleobj2.a, sampleobj2.b)

How do I clone an object (here sampleobj1) instead of manually assigning all variables of "sample" to self? I get the following error:

Traceback (most recent call last):
File "test.py", line 17, in <module>
print (sampleobj2.a, sampleobj2.b)
AttributeError: 'test' object has no attribute 'a'

Why doesn't the line: self = sample work? Whatever I do, I always happen to get the same error. Individually copying the attributes seem just fine. But I am working on a code with a lot of attributes where copying each attribute seems a bit lengthy.

sampleobj3 = copy(sampleobj1) also seems to work. But I want the copying to be done in the class & not in the main of the program.


Solution

  • The line self = sample only overwrites a local variable, it does not replace the object initially stored in self in memory.

    To copy instances of a class, you have to fully define how to build a new object from an existing one.

    You do this by defining the __copy__ and __deepcopy__ methods. These are the dunder methods used by copy.copy and copy.deepcopy respectively.

    Furthermore, note that it is bad practice to have input in your __init__ as it impedes the above solution. You should separate your logic and your IO.

    import copy
    
    class test():
        def __init__(self, a, b):
            self.a, self.b = a, b
    
        def __copy__(self):
            return type(self)(self.a, self.b)
    
    # Here we encapsulate the IO part of your code
     def test_factory():
        a = int(input())
        b = int(input())
        return test(a, b)
    
    foo = test_factory()
    ... # input the attributes
    bar = copy.copy(foo) # a copy of your object