Create a list property in Python
Question: I am starting OOP with Python 3 and I find the concept of `property` really
interesting.

I need to encapsulate a private list, but how could I use this paradigm for
lists?

Here's my naive try:

    
    
    class Foo:
        """ Naive try to create a list property.. and obvious fail """
    
        def __init__(self, list):
            self._list = list
    
        def _get_list(self, i):
            print("Accessed element {}".format(i))
            return self._list[i]
    
        def _set_list(self, i, new):
            print("Set element {} to {}".format(i, new))
            self._list[i] = new
    
        list = property(_get_list, _set_list)
    

This doesn't behave as expected and even makes python crash when I try the
following code. This is the fictive behavior I would like `Foo` to exhibit:

    
    
    >>> f = Foo([1, 2, 3])
    >>> f.list
    [1, 2, 3]
    >>> f.list[1]
    Accessed element 1
    2
    >>> f.list[1] = 12
    Set element 1 to 12
    >>> f.list
    [1, 12, 3]
    


Answer: 
    import collections
    
    
    class PrivateList(collections.MutableSequence):
        def __init__(self, initial=None):
            self._list = initial or []
    
        def __repr__(self):
            return repr(self._list)
    
        def __getitem__(self, item):
            print("Accessed element {}".format(item))
            return self._list[item]
    
        def __setitem__(self, key, value):
            print("Set element {} to {}".format(key, value))
            self._list[key] = value
    
        def __delitem__(self, key):
            print("Deleting element {}".format(key))
            del self._list[key]
    
        def __len__(self):
            print("Getting length")
            return len(self._list)
    
        def insert(self, index, item):
            print("Inserting item {} at {}".format(item, index))
            self._list.insert(index, item)
    
    
    class Foo(object):
        def __init__(self, a_list):
            self.list = PrivateList(a_list)
    

Then runnning this:

    
    
    foo = Foo([1,2,3])
    print(foo.list)
    print(foo.list[1])
    foo.list[1] = 12
    print(foo.list)
    

Outputs:

    
    
    [1, 2, 3]
    Accessed element 1
    2
    Set element 1 to 12
    [1, 12, 3]
    

