If your goal is to make it so that users of your class can safely call copy.copy
on its instances, then by all means feel free to add a __copy__
method:
def __copy__(self):
return self
However, this isn't really necessary. The documentation for your class should make it clear that its instances are immutable, so anyone using your class should know that they can safely re-use an instance if they want to refer to it in multiple places, just like they do with the built-in immutable types like int
, str
, tuple
, and frozenset
. Eg,
a, b, c = Immutable(123), Immutable(456), 42
d = {'one': a, 'two': b, 'three': c}
If you don't supply a __copy__
method and someone does call copy.copy
on an instance, then they'll get a new object that's a clone of the original instance. With __copy__
defined as above they will of course just get a reference to the original object.
BTW, you should make .field
(and any other attributes) into a property, and don't supply a setter.
class Immutable:
def __init__(self, field):
self._field = field
@property
def field(self):
return self._field
And now you can call the field method as if it were a simple attribute:
a = Immutable(123)
print(a.field)
Of course, you can still mutate the ._field
attribute in the normal way, but anyone using your class ought to know they aren't supposed to do that. :)
In the question comments we discussed the fact that calling copy.copy
on a tuple returns a reference to the original tuple, even though tuple
doesn't define __copy__
. None of the built-in types define __copy__
, but bear in mind that they are all defined in C, so they work a little differently to classes defined in Python. FWIW, calling copy.copy
on any of the built-in immutable types returns a reference to the original object, and calling copy.copy
on any of the built-in mutable types returns a clone.