1.11M Members

Expose an immutable sequence

 
2
 

This snippet is easy: it defines an immutable wrapper around a sequence type (list, deque, etc) which allows a class, function or module to expose a read only version of a sequence to the outer world. A constant wrapper around mapping types could also be defined in a similar manner.

class ConstSequence(object):
    """Immutable wrapper around a sequence type instance."""
    _SliceType = type(slice(None)) # <-- this should work for all versions of python
    def __init__(self, seq):
        if isinstance(seq, ConstSequence):
            seq = seq._adaptee
        self._adaptee = seq
    
    def __getitem__(self, key):
        if isinstance(key, self._SliceType):
            return ConstSequence(self._adaptee[key])
        else:
            return self._adaptee[key]
        
    def __len__(self):
        return len(self._adaptee)

    def __contains__(self, key):
        return key in self._adaptee
    
    def __iter__(self):
        return (x for x in self._adaptee)
    
    def __reversed__(self):
        return (x for x in reversed(self._adaptee))

    def __str__(self):
        return 'ConstSequence(%r)' % self._adaptee

    __repr__ = __str__

if __name__ == "__main__":
    # example use
    class A(object):
        """Class A stores a list internally, but exposes a read-only version
        of this list.
        """
        def __init__(self):
            self._items = list()
            self.items = ConstSequence(self._items)
        
        def add_string(self, s):
            "Methods in class A can alter the list's content"
            self._items.extend(s)
    a = A()
    a.add_string("hello")
    print a.items[1] # prints 'e' : client code can read the list
    a.items[1] = "z" # raises TypeError : client code can't alter the list's content
 
1
 

But:

class ConstSequence(object):
    "Read-only wrapper around a sequence type instance"
    def __init__(self, seq):
        if isinstance(seq, ConstSequence):
            seq = seq._adaptee
        self._adaptee = seq
    
    def __getitem__(self, key):
        import types
        if isinstance(key, types.SliceType):
            return ConstSequence(self._adaptee[key])
        else:
            return self._adaptee[key]
        
    def __len__(self):
        return len(self._adaptee)

    def __contains__(self, key):
        return key in self._adaptee
    
    def __iter__(self):
        return (x for x in self._adaptee)
    
    def __reversed__(self):
        return (x for x in reversed(self._adaptee))

    def __str__(self):
        return 'ConstSequence(%s)' % self._adaptee

    __repr__ = __str__
    
if __name__ == "__main__":
    # example use
    class A(object):
        """Class A stores a list internally, but exposes a read-only version
        of this list.
        """
        def __init__(self):
            self._items = list()
            self.items = ConstSequence(self._items)
        
        def add_string(self, s):
            "Methods in class A can alter the list's content"
            self._items.extend(s)

        def __str__(self):
            return 'A(%s)' % self.items

        __repr__ = __str__

    a = A()
    a.add_string("hello")
    a.add_string([[1, 2, 3]])
    print a
    print a.items[1] # prints 'e' : client code can read the list
    a.items[-1][-1] = 'Gaboom!'
    print a  # list in ConstSequence is not constant
    a.items[1] = "z" # raises TypeError : client code can't alter the list's content
 
1
 

Yes, it's the same problem with tuples

t = (1, 2, ["hello", "world"])
print(t)
t[-1][-1] = "daniweb"
print(t)
""" my output -->
(1, 2, ['hello', 'world'])
(1, 2, ['hello', 'daniweb'])
"""

Immutability never meant true immutability in python. If ConstSequences are immutable like tuples are, it's ok for me.
I approve adding a __str__ method. You could have included the missing 'import types' out of the __getitem__ method.

 
1
 

Line 9
if isinstance(key, types.SliceType):
can be changed to
if isinstance(key, slice):
to work with Python27 and Python33

 
0
 

Thanks. I don't know why they removed types.SliceType in python 3.

Isn't it about time forums rewarded their contributors?

Earn rewards points for helping others. Gain kudos. Cash out. Get better answers yourself.

It's as simple as contributing editorial or replying to discussions labeled or OP Kudos

You
This is an OP Kudos discussion and contributors may be rewarded
Post:
Start New Discussion
View similar articles that have also been tagged: