Python Defensive Iteration

This is the item 12 explained in the "Effective Python", by Brett Slatkin. Generators are the best save of out of memory problem. Here the problem,

class StringToList(object):
    def __init__(self, text):
        self.text = text

    def __iter__(self):
        for x in self.text:
            yield x

words = StringToList('Hello')

# case 1
it = iter(words)
it2 =iter(it)
print(it, it2) #(<generator object __iter__ at 0x10816d7d0>, <generator object __iter__ at 0x10816d7d0>)
next(it) # 'H'
next(it2) # 'e'

The problem is it and it2 pointing to the same instance and iteration is not as expected ('it2' give a next element as 'e' instead 'H'). To overcome this problem, author has suggested the following solution which is applicable to set and dict as well. In the case 1, same container is used. But in the case 2, different containsers.

# case 2
it = iter(words)
it2 =iter(words)
print(it, it2) # (<generator object __iter__ at 0x10816d550>, <generator object __iter__ at 0x10816d320>)
next(it) # 'H'
next(it2) # 'H'

In the above code, diffrent instaces because two diffrent containers. To defence from the case 1, need to use the following defence and avoid:

if it is it2:
    raise TypeError('Same container error')
else:
    print(next(it)) # 'H'
    print(next(it2)) # 'H'

That will promote the case 2 style of programming.

Comments

Popular posts from this blog

How To: GitHub projects in Spring Tool Suite

Spring 3 Part 7: Spring with Databases

Parse the namespace based XML using Python