Another possibility would be to return instances of my own ImmutableList
class. It solves 2 and 3, but not 1 (because I will have to copy the list
instances to initialize ImmutableList
instances) neither 4.
If you returned an immutable tuple
instance from a mutable list
instance it would perform a shallow copy (e.g. tuple([1, 2, 3])
), but if you return your own ImmutableList
instance you don’t have to perform any copy at initialization since you can store a reference to the mutable list
instance. ImmutableList
will be a protection proxy providing a read-only dynamic view on the mutable list
instance (i.e. you cannot update the mutable list
instance from the ImmutableList
instance but changes to the mutable list
instance will reflect in the ImmutableList
instance):
import collections.abc
import datetime
class Event:
def __init__(self, id_):
self._id = id_
def get_id(self):
return self._id
class ImmutableList(collections.abc.Sequence):
def __init__(self, list_):
self._list = list_
def __getitem__(self, index):
return self._list[index]
def __len__(self):
return len(self._list)
class Calendar:
def __init__(self):
self._dict = collections.defaultdict(list)
def add_event(self, date, event):
self._dict[date].append(event.get_id())
def get_event_ids(self, date):
return ImmutableList(self._dict[date])
>>> c = Calendar()
>>> d = datetime.date.today()
>>> c.add_event(d, Event('birthday'))
>>> l = c.get_event_ids(d)
>>> del l[0] # read-only view
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'ImmutableList' object doesn't support item deletion
>>> list(l)
['birthday']
>>> c.add_event(d, Event('christmas'))
>>> list(l) # dynamic view
['birthday', 'christmas']
Note that in this solution, the Calendar
class stores and updates the mutable list
instances directly and only wraps them in ImmutableList
instances when returned from the Calendar.get_event_ids
function. It differs from @aquavitae’s solution where the Calendar
class stores and updates the mutable list
instances from ImmutableList
instances by accessing their internal attributes, thereby coupling the ImmutableList
class with the Calendar
class, which compromises information hiding (also known as encapsulation).