0

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.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Kael
  • 92
  • 1
  • 8

1 Answers1

4

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
Olivier Melançon
  • 21,584
  • 4
  • 41
  • 73
  • The problem is that I have a lot of attributes have to be made as a parameter (not possible). Do we always have to overwrite the __copy__ and __deepcopy__ methods & manually assign all the object parameters? – Kael Sep 15 '18 at 13:51
  • 2
    Yes, although if you have many attributes, you can craft your `__init__` to return an empty object and make `__copy__` fill it in with `self.__dict__` – Olivier Melançon Sep 15 '18 at 14:00