views:

112

answers:

2

i don't know "self._iterator = iter(self._container)"in next code.

in django.http :

class HttpResponse(object):
    def __iter__(self):
        self._iterator = iter(self._container)
        return self

    def next(self):
        chunk = self._iterator.next()
        if isinstance(chunk, unicode):
            chunk = chunk.encode(self._charset)
        return str(chunk)

i read the api :

Return an iterator object. The first argument is interpreted very differently depending on the presence of the second argument. Without a second argument, o must be a collection object which supports the iteration protocol (the __iter__() method), or it must support the sequence protocol (the __getitem__() method with integer arguments starting at 0). If it does not support either of those protocols, TypeError is raised. If the second argument, sentinel, is given, then o must be a callable object. The iterator created in this case will call o with no arguments for each call to its next() method; if the value returned is equal to sentinel, StopIteration will be raised, otherwise the value will be returned. One useful application of the second form of iter() is to read lines of a file until a certain line is reached. The following example reads a file until "STOP" is reached:

but i also don't know what the iter function made .

i know the __iter__:
class a(object):
    def __init__(self,x=10):
        self.x = x
    def __iter__(self):
        return self
    def next(self):
        if self.x > 0:
                self.x-=1
                return self.x
        else:
                raise StopIteration

Please try to use the code, rather than text, because my English is not very good, thank you

A: 

HttpResponse is a class that can store string data. The data is stored in a member variable called _container.

Suppose hr is an instance of HttpResponse with data inside it. When you call iter(hr) then you should get back an iterator. This iterator will return data from the _container member variable.

This class "wraps" the _container member so that it can always return non-Unicode text. Because this class has a __iter__() method function, when you call iter() you are really calling the special __iter__() method function. This method function actually does call iter() on the _container member variable to get an iterator for its contents. But then it saves this iterator in the _iterator member variable, and returns self. Now it is ready to iterate.

There is a next() method function defined. If the type of the _container variable is Unicode, it calls encode() to encode the Unicode in some encoding and return non-Unicode. It uses another member variable, _charset, to know which charset to use for the encoding. If the type of the container variable is not Unicode, it must be an ordinary string type, and the data is simply returned unchanged.

In this way, the object "wrapped" in this class can be iterated and always return non-Unicode text.

I am surprised by this implementation of the iterator protocol. When it returns an iterator to you, it is just returning self, so if you call iter() twice, you do not actually get two usable iterators back. This seems like it could be dangerous. I guess Django code never does anything like that.

steveha
+1  A: 

An iterator can be iterated:

for item in mylist:
    print item

for key,item in enumerate(mylist):
    print key,":",item

for i in range(0,50):
    print i

To use for item in X, X must be iterable.

You can make your class iterable by adding next(self) etc, as in your sample. So with

class a(object):
    def __init__(self,x=10):
        self.x = x
    def __iter__(self):
        return self
    def next(self):
        if self.x > 0:
            self.x-=1
            return self.x
        else:
            raise StopIteration

Then you can do

 ainst = a()
 for item in aisnt:
     print item
Phil H