1,105,417 Community Members

Expose an immutable sequence

Member Avatar
Reputation Points: 1,140 [?]
Q&As Helped to Solve: 884 [?]
Skill Endorsements: 18 [?]
 
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
Member Avatar
pyTony
pyMod
6,104 posts since Apr 2010
Reputation Points: 818 [?]
Q&As Helped to Solve: 1,056 [?]
Skill Endorsements: 42 [?]
Moderator
Featured
 
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
Member Avatar
Gribouillis
Posting Maven
3,456 posts since Jul 2008
Reputation Points: 1,140 [?]
Q&As Helped to Solve: 884 [?]
Skill Endorsements: 18 [?]
Moderator
 
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.

Member Avatar
Ene Uran
Posting Virtuoso
1,822 posts since Aug 2005
Reputation Points: 610 [?]
Q&As Helped to Solve: 278 [?]
Skill Endorsements: 10 [?]
 
1
 

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

Member Avatar
Gribouillis
Posting Maven
3,456 posts since Jul 2008
Reputation Points: 1,140 [?]
Q&As Helped to Solve: 884 [?]
Skill Endorsements: 18 [?]
Moderator
 
0
 

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

You
Post:
Start New Discussion
View similar articles that have also been tagged: