7stud wrote: > Hi, > > Thanks for the responses. > >> 7stud <[EMAIL PROTECTED]> wrote: >>> Can you explain some of the details of why this code fails: >> --- >> class Parrot(object): >> def __iter__(self): >> return self >> def __init__(self): >> self.next = self.next().next >> def next(self): >> for word in "Norwegian Blue's have beautiful >> plumage!".split(): >> yield word >> >> P = Parrot() >> for word in P: >> print word >> ------ > > On Apr 18, 8:45 pm, [EMAIL PROTECTED] (Alex Martelli) wrote: >> ...a loop like "for x in y:" binds an unnamed temporary >> variable (say _t) to iter(y) and then repeatedly calls _t.next() [or to >> be pedantic type(_t).next(t)] until that raises StopIteration. > > > Aiiii. Isn't this the crux: > >> repeatedly calls....[type(_t).next(t)] > > As far as I can tell, if the call was actually _t.next(), the code I > asked about would work. However, the name look up for 'next' when you > call: > [snip wild goose chase that appears to miss the main point].
It's nothing to do with the name lookup. Alex mentioned that to remind us that the magic "double-under" names are looked up on the type rather than the instance, so messing around with instances won't change the behavior. [This is not true of "old-style" or "classic" classes, which we should be eschewing in preparation for their disappearance]. You have to understand the iterator protocol, which is how the language interacts with objects whose contents it iterates over (for example in for loops). When you iterate over an object X then the *interpreter*, under the hood, initializes the loop by calling iter(X) and stashing the result away as, let's say, _t. Every time a new value is needed in the iteration _t.next() is called to produce it. We can see this if we open a file: >>> f = open("travel.txt") >>> f.__iter__() <open file 'travel.txt', mode 'r' at 0x7ff1f6e0> >>> f.next() 'Virgin Flight booking extension 33024 Louise reference 1VV75R\r\n' >>> Calling the file's .next() method produces the next line in the file. The point is that a function with "yield" expressions in it, when called, returns a generator object. So if an instance's next() method contains yield statements then repeated calls to it give you an (endless) sequence of generator objects. Here's a simple object class that adheres to the iterator protocol: >>> class myI(object): ... def __init__(self, lim): ... self.lim = lim ... self.current = 0 ... def __iter__(self): ... return self ... def next(self): ... self.current += 1 ... if self.current > self.lim: ... raise StopIteration ... return self.current # NOT yield! ... >>> myi = myI(5) >>> for i in myi: ... print i ... 1 2 3 4 5 >>> I hope this helps. You appear to be forming a rather over-complex model of the way Python behaves. Think "simple" - Python tries to be as simple as it can to achieve its objectives. regards Steve -- Steve Holden +44 150 684 7255 +1 800 494 3119 Holden Web LLC/Ltd http://www.holdenweb.com Skype: holdenweb http://del.icio.us/steve.holden Recent Ramblings http://holdenweb.blogspot.com -- http://mail.python.org/mailman/listinfo/python-list