Re: What makes an iterator an iterator?
On Thu, 19 Apr 2007 20:00:31 -0700, Alex Martelli wrote: > class sane(object): > def __init__(self, sentence='four scores and twenty years ago'): > def agenerator(): > for word in sentence.split(): yield word > self._thegen = agenerator() > def __iter__(self): return self > def next(self): return self._thegen.next() Nice technique! I always forget about nesting functions like that. I should use it more often. -- Steven D'Aprano -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
Steven D'Aprano <[EMAIL PROTECTED]> wrote: > > Calling a generator, such as this next method, returns an iterator > > object; calling it repeatedly returns many such iterator objects, and > > never raises StopIteration, thus obviously producing an unending loop. > > Thank you for that answer Alex, even though I didn't ask the question I > was wondering the same thing myself. You're welcome -- refreshing to see somebody who can actually understand and accept the answer, rather than going on unrelated tangents when one tries to help them:-). Alex -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
7stud <[EMAIL PROTECTED]> wrote: ... > > 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 All of your following lamentations are predicated on this assumption, it would seem. Very well, let's put it to the text, as Python makes it so easy..: >>> class sic: pass ... >>> _t = sic() >>> def nexter(): ... yield 23 ... >>> _t.next = nexter >>> for i in range(10): ... print _t.next() ... See? a loop that calls _t.next() and only terminates when that raises StopIteration will never exit when _t.next is a generator function (as opposed to *the result of calling* a generator function, which is an *iterator object*). This applies when _t.next is looked up on the instance, as we ensured we were in this toy example, just as much as when it's coming from type(_t) -- which is why in this context the distinction is pedantic, and why it was definitely not crucial, as you appear (on the basis of this false idea you have) to think it was, in the Nutshell (where I went for readability rather than pedantic precision in this instance). If you want to implement a class whose next method internally uses a generator, that's pretty easy, e.g.: class sane(object): def __init__(self, sentence='four scores and twenty years ago'): def agenerator(): for word in sentence.split(): yield word self._thegen = agenerator() def __iter__(self): return self def next(self): return self._thegen.next() there -- easy, innit? You just have to understand the difference between calling a generator function, and calling the next method of the object (iterator) which is returned by that function when called:-). Alex -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
7stud wrote: > On Apr 19, 5:37 am, Steve Holden <[EMAIL PROTECTED]> wrote: >> 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... > > P.next() > > vs. > > type(P).next() > > Where is the "double-under" name? > Try and stick with the main party. Here is the exact exchange (between Steven D'Aprano and Alex) to which I referred: > Steven D'Aprano <[EMAIL PROTECTED]> wrote: > >> > I thought that an iterator was any object that follows the iterator >> > protocol, that is, it has a next() method and an __iter__() method. > > The special methods need to be on the type -- having attributes of those > names on the instance doesn't help (applies to all special methods in > the normal, aka newstyle, object model; legacy, aka classic, classes, > work by slightly different and not entirely self-consistent semantics). So if you have a beef, it would appear to be with Alex? 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
Re: What makes an iterator an iterator?
On Apr 19, 3:12 pm, 7stud <[EMAIL PROTECTED]> wrote: > On Apr 19, 5:37 am, Steve Holden <[EMAIL PROTECTED]> wrote: > > > > > 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... > > P.next() > > vs. > > type(P).next() > > Where is the "double-under" name? The following example looks up next() in the instance not the class: class Parrot(object): def __init__(self): self.next = lambda: "hello" def __iter__(self): return self def next(self): yield "goodbye" raise StopIteration p = Parrot() _t = iter(p) print _t.next() -output: hello -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
On Apr 19, 5:37 am, Steve Holden <[EMAIL PROTECTED]> wrote: > > 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... P.next() vs. type(P).next() Where is the "double-under" name? -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
"7stud" <[EMAIL PROTECTED]> wrote in message news:[EMAIL PROTECTED] | On Apr 18, 8:38 pm, "Terry Reedy" <[EMAIL PROTECTED]> wrote: | > | > One very good way to get an iterator from an iterable is for .__iter__ to | > be a generator function. | | Ahhh. That eliminates having to deal with next().next constructs. There never was any 'having' to deal with such a thing. I suggest completely forgetting .next().next and variants. | Nice. | | > snip all examples of bad code that violate the iterator rule | > by improperly writing .next as a generator function | | What iterator rule states that .next can't be a generator function? How about the programming rule that a function should return what you want it to return, or at least something 'close'? I gave the iterator rule in brief at the top of my posting, but here is again with several more words: the next method of an iterator for an actual or virtual collection has no input other than self (and internally stored information). Each time it is called, its output is either 'another' object in the collection, if there is at least one, or a StopIteration exception. For sequences, 'another' most be the next item after the last one returned (if any). Whether or not duplicates are allowed depends on the collection type. Each call of a generator function returns a new generator object. It never raises StopIteration. So making .next a generator function defines the collection as an infinite virtual collection (sequence or multiset) of generators. If that is what is intended (which it is not in the examples posted), fine. Otherwise, it is a mistake. | My book says an iterator is any object with a .next method that is | callable without arguments (Python in a Nutshell(p.65) says the same | thing). A complete interface specification specifies information flows in both directions, as I did before and again here. | I've read recommendations that an iterator should additionally contain | an __iter__() method, but I'm not sure why that is. In particular PEP | 234 says: [snip] should [snip] In my view, the 'should' should be taken strongly, so that the iterator is also an iterable. It is certainly idiomatic to follow the advice. Then one can write code like def f(iterable): iterator = iter(iterable) instead of def f(iterable): try: iterator = iter(iterable) except AttributeError: pass Terry Jan Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
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. > > > A. 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__() >>> 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
Re: What makes an iterator an iterator?
On Wed, 18 Apr 2007 19:45:50 -0700, Alex Martelli wrote: > 7stud <[EMAIL PROTECTED]> wrote: >... >> Can you explain some of the details of why this code fails: >... >> def next(self): >> for word in "Norwegian Blue's have beautiful >> plumage!".split(): >> yield word > > Sure, easily: 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. > > Calling a generator, such as this next method, returns an iterator > object; calling it repeatedly returns many such iterator objects, and > never raises StopIteration, thus obviously producing an unending loop. Thank you for that answer Alex, even though I didn't ask the question I was wondering the same thing myself. -- Steven. -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
On Wed, 18 Apr 2007 01:45:10 -0700, Paul McGuire wrote: >> For the record, this is what I actually wanted: a four-line self-sorting >> dictionary: >> >> class SortedDict(dict): >> def __iter__(self): >> for key in sorted(self.keys()): >> yield key [snip] > Very neat. Why not this? > > class SortedDict(dict): > def __iter__(self): > return iter(sorted(self.keys())) Good question. I don't have a good answer except for "because I didn't think of it". -- Steven. -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
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. A. 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: P.next() is entirely different from the name look up for 'next' when you call: type(P).next(). In the first lookup, the instance attribute "next" hides the class attribute "next". In the second lookup, the "next" attribute of the class is returned, i.e. the next() method. Yet, a generator-function- call returns an iterator object that wraps the generator function, so when the for loop makes repeated calls to type(P).next(), an iterator object is repeatedly returned--what you want is i.next() to be returned. I suspected next() might be called through the class, but after carefully parsing the section on iterators (Python in a Nutshell, p. 65) where it says iter() returns an object i, and then the for loop repeatedly calls i.next(), I dismissed that idea. I have to admit I'm still a little confused by why you only parenthetically noted that information and called it pedantic. On Apr 18, 8:38 pm, "Terry Reedy" <[EMAIL PROTECTED]> wrote: > > One very good way to get an iterator from an iterable is for .__iter__ to > be a generator function. Ahhh. That eliminates having to deal with next().next constructs. Nice. > snip all examples of bad code that violate the iterator rule > by improperly writing .next as a generator function What iterator rule states that .next can't be a generator function? My book says an iterator is any object with a .next method that is callable without arguments (Python in a Nutshell(p.65) says the same thing). Also, my boos says an iterable is any object with an __iter__ method.As a result, next() and __iter__() don't have to be in the same object: lass MyIterator(object): def __init__(self, obj): self.toIterateOver = obj def next(self): for x in range(self.toIterateOver.age): print x raise StopIteration class Dog(object): def __init__(self, age): self.age = age def __iter__(self): return MyIterator(self) d = Dog(5) for year in d: print year I've read recommendations that an iterator should additionally contain an __iter__() method, but I'm not sure why that is. In particular PEP 234 says: -- Classes can define how they are iterated over by defining an __iter__() method; this should take no additional arguments and return a valid iterator object. A class that wants to be an iterator should implement two methods: a next() method that behaves as described above, and an __iter__() method that returns self. The two methods correspond to two distinct protocols: 1. An object can be iterated over with "for" if it implements __iter__() or __getitem__(). 2. An object can function as an iterator if it implements next(). Container-like objects usually support protocol 1. Iterators are currently required to support both protocols. The semantics of iteration come only from protocol 2; protocol 1 is present to make iterators behave like sequences; in particular so that code receiving an iterator can use a for-loop over the iterator. Classes can define how they are iterated over by defining an __iter__() method; this should take no additional arguments and return a valid iterator object. A class that wants to be an iterator should implement two methods: a next() method that behaves as described above, and an __iter__() method that returns self. The two methods correspond to two distinct protocols: 1. An object can be iterated over with "for" if it implements __iter__() or __getitem__(). 2. An object can function as an iterator if it implements next(). Container-like objects usually support protocol 1. Iterators are currently required to support both protocols. The semantics of iteration come only from protocol 2; protocol 1 is present to make iterators behave like sequences; in particular so that code receiving an iterator can use a for-loop over the iterator. >The semantics of >iteration come only from protocol 2 My example demonstrate
Re: What makes an iterator an iterator?
7stud <[EMAIL PROTECTED]> wrote: ... > Can you explain some of the details of why this code fails: ... > def next(self): > for word in "Norwegian Blue's have beautiful > plumage!".split(): > yield word Sure, easily: 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. Calling a generator, such as this next method, returns an iterator object; calling it repeatedly returns many such iterator objects, and never raises StopIteration, thus obviously producing an unending loop. Alex -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
An iterator is an object with a .__iter__ method that returns self and a .next method that either returns an object or raises StopIteration. One very good way to get an iterator from an iterable is for .__iter__ to be a generator function. When called, it returns an generator with .__iter__ and .next methods that work as specified. words = "Norwegian Blues have beautiful plumage!".split() print words prints ['Norwegian', 'Blues', 'have', 'beautiful', 'plumage!'] class Parrot(object): def __init__(self, words): self.words = words def __iter__(self): for word in words: yield word for word in Parrot(words): print word prints Norwegian Blues have beautiful plumage! One can also make an iterable an (self) iterator by correctly writing the two needed methods. class Parrot2(object): def __init__(self, words): self.words = words def __iter__(self): self.it = -1 return self def next(self): self.it += 1 try: return self.words[self.it] except IndexError: raise StopIteration for word in Parrot2(words): print word which prints the same 5 lines. However, when an object is its own iterator, it can only be one iterator at a time (here, pointing at one place in the word list), whereas the first method allows multiple iterators (here, possibly pointing to different places in the list. | Can you explain some of the details of why this code fails: [snip all examples of bad code that violate the iterator rule by improperly writing .next as a generator function] I think most people should learn how to write iterators correctly, as I gave examples of above, rather than worry about the details of how and why mis-written code fails with a particular version of a particular implementation. So I won't go down that road. Terry Jan Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
On Apr 18, 8:50 am, [EMAIL PROTECTED] (Alex Martelli) wrote: > The special methods need to be on the type -- having attributes of those > names on the instance doesn't help (applies to all special methods in > the normal, aka newstyle, object model; legacy, aka classic, classes, > work by slightly different and not entirely self-consistent semantics). > > Alex 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 -- It causes an infinite loop that just prints out the iterator object returned when you call the generator function. If I try this: - class Parrot(object): def __iter__(self): return self def __init__(self): print self.next() print self.next().next #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 ''' -- the output is: Based on that output, self.next() is the iterator object that wraps the generator function, and it has a next() method. If 'i' is the iterator object, then the statement: self.next = self.next().next is equivalent to: self.next = i.next and therefor calling P.next() is equivalent to i.next(), which appears to be exactly what you want. As I understand it, this is how the for loop works: 1) The for loop causes the built in, global iter() function to be called with P as an argument: iter(P). That calls P's __iter__() method, which just returns P. 2) The for loop repeatedly calls next() on whatever object is returned by 1), so that results in calls to P.next(). 3) P.next() is equivalent to i.next() I don't understand at which step does the code fail. -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
On Apr 18, 10:36 am, [EMAIL PROTECTED] wrote: > > I find myself perplexed as to this behaviour. > > You can not iterate over a dead object! It's not dead, it's restin'. All shagged out over a long squak. -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
> I find myself perplexed as to this behaviour. You can not iterate over a dead object! -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
Steven D'Aprano <[EMAIL PROTECTED]> wrote: > I thought that an iterator was any object that follows the iterator > protocol, that is, it has a next() method and an __iter__() method. The special methods need to be on the type -- having attributes of those names on the instance doesn't help (applies to all special methods in the normal, aka newstyle, object model; legacy, aka classic, classes, work by slightly different and not entirely self-consistent semantics). Alex -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
Sorry, my previous post was incomplete. I didn't realized that you implemented _next() as a generator funcition. Besides changing __init__() from self.next = self._next() to self.next = self._next you need to implement __iter__() as: return self.next() > class Parrot(object): > def __iter__(self): > return self > def __init__(self): > self.next = self._next() > def _next(self): > for word in "Norwegian Blue's have beautiful plumage!".split(): > yield word > -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
> > class Parrot(object): > def __iter__(self): > return self > def __init__(self): Typo right here > self.next = self._next() write: self.next = self._next no parenthesis. > def _next(self): > for word in "Norwegian Blue's have beautiful plumage!".split(): > yield word > See previous explanation. thanks, - Isaac. -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
Stefan Rank schrieb: > on 18.04.2007 07:39 Steven D'Aprano said the following: >> I thought that an iterator was any object that follows the iterator > > replace object with "instance of a class", i.e. the relevant methods are > looked up in the __class__ not in the instance (I think). > I had the same troubles trying to dynamically reassign a __call__ method... This is correct. It's not properly documented though, and not applied consistently, e.g. __enter__ and __exit__ are looked up in the instance itself. Georg -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
Steven D'Aprano wrote: > class SortedDict(dict): > def __iter__(self): > for key in sorted(self.keys()): > yield key > > Note that using sorted(self) does not work. That's because sorted() invokes __iter__() if present. To prevent the recursion you can explicitly invoke dict.__iter__(): >>> class SortedDict(dict): ... def __iter__(self): ... return iter(sorted(super(SortedDict, self).__iter__())) ... >>> sd = SortedDict(a=1, b=2, c=3) >>> list(sd) ['a', 'b', 'c'] Note that a list of keys is still built before the first key is yielded, and, unlike dict, you can modify your SortedDict while iterating over it: >>> for k in sd: ... if k == "b": sd["x"] = 42 ... >>> sd {'a': 1, 'x': 42, 'c': 3, 'b': 2} whereas: >>> d = dict(a=1, b=2, c=3) >>> for k in d: ... if k == "b": d["x"] = 42 ... Traceback (most recent call last): File "", line 1, in RuntimeError: dictionary changed size during iteration By the way, I think it would be worthwile to change super() to allow e. g. super(SomeClass, self)[...] as an alternate spelling for super(SomeClass, self).__getitem__(...) etc. With such an enhancement SortedDict would become class SortedDict(dict): def __iter__(self): # doesn't work in current Python iter(sorted(super(SortedDict, self))) Peter -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
On Apr 18, 3:32 am, Steven D'Aprano <[EMAIL PROTECTED]> wrote: > On Wed, 18 Apr 2007 06:13:39 +, I V wrote: > > On Wed, 18 Apr 2007 15:39:22 +1000, Steven D'Aprano wrote: > >> I thought that an iterator was any object that follows the iterator > >> protocol, that is, it has a next() method and an __iter__() method. > > [snip] > > > i.e., just rename your _next function to __iter__ . Your class won't > > itself be an iterator, but it will be usable in for statements and so one, > > and convertable to an iterator with the iter builtin. > > Thanks to all those who helped, this fixed my problem. > > For the record, this is what I actually wanted: a four-line self-sorting > dictionary: > > class SortedDict(dict): > def __iter__(self): > for key in sorted(self.keys()): > yield key > > Note that using sorted(self) does not work. > > Iterating over a SortedDictionary returns the keys in sorted order. This > minimalist implementation doesn't sort the values, items or string > representation of the dict, but they should be easy to implement. > > -- > Steven D'Aprano Very neat. Why not this? class SortedDict(dict): def __iter__(self): return iter(sorted(self.keys())) -- Paul -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
On Wed, 18 Apr 2007 06:13:39 +, I V wrote: > On Wed, 18 Apr 2007 15:39:22 +1000, Steven D'Aprano wrote: >> I thought that an iterator was any object that follows the iterator >> protocol, that is, it has a next() method and an __iter__() method. [snip] > i.e., just rename your _next function to __iter__ . Your class won't > itself be an iterator, but it will be usable in for statements and so one, > and convertable to an iterator with the iter builtin. Thanks to all those who helped, this fixed my problem. For the record, this is what I actually wanted: a four-line self-sorting dictionary: class SortedDict(dict): def __iter__(self): for key in sorted(self.keys()): yield key Note that using sorted(self) does not work. Iterating over a SortedDictionary returns the keys in sorted order. This minimalist implementation doesn't sort the values, items or string representation of the dict, but they should be easy to implement. -- Steven D'Aprano -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
On Wed, 18 Apr 2007 16:58:23 +1000, Ben Finney wrote: > Steven D'Aprano <[EMAIL PROTECTED]> writes: > >> class Parrot(object): >> def __iter__(self): >> return self >> def __init__(self): >> self.next = self._next() >> def _next(self): >> for word in "Norwegian Blue's have beautiful plumage!".split(): >> yield word > > Clearly the problem is you've misused an apostrophe. Python doesn't > like the plural getting an apostrophe. > > http://www.angryflower.com/bobsqu.gif> I thought the rule wa's that any time you 'see an 'S, you put an apo'strophe before it. If that's wrong, 'shouldn't it rai'se an exception? -- 'Steven D'Aprano -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
on 18.04.2007 07:39 Steven D'Aprano said the following: > I thought that an iterator was any object that follows the iterator replace object with "instance of a class", i.e. the relevant methods are looked up in the __class__ not in the instance (I think). I had the same troubles trying to dynamically reassign a __call__ method... > protocol, that is, it has a next() method and an __iter__() method. > > But I'm having problems writing a class that acts as an iterator. I have: > > class Parrot(object): > def __iter__(self): > return self > def __init__(self): > self.next = self._next() > def _next(self): > for word in "Norwegian Blue's have beautiful plumage!".split(): > yield word Try this:: class Parrot(object): def __iter__(self): return self def __init__(self): self.__class__.next = self._next().next # see post by I V def _next(self): for word in "Norwegian Blue's have beautiful plumage!".split(): yield word This works but practically forces the class to be used as a singleton... not very helpful :) Better: * use the '__iter__ returns/is a generator' way, * or if you need the object to be the iterator, implement the next method directly on the class:: class Parrot(object): def _next(self): for word in "Norwegian Blue's have beautiful plumage!".split(): yield word def __iter__(self): self.generator = self._next() return self def next(self): return self.generator.next() cheers, stefan -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
Steven D'Aprano <[EMAIL PROTECTED]> writes: > class Parrot(object): > def __iter__(self): > return self > def __init__(self): > self.next = self._next() > def _next(self): > for word in "Norwegian Blue's have beautiful plumage!".split(): > yield word Clearly the problem is you've misused an apostrophe. Python doesn't like the plural getting an apostrophe. http://www.angryflower.com/bobsqu.gif> -- \ "Speech is conveniently located midway between thought and | `\ action, where it often substitutes for both." -- John Andrew | _o__) Holmes, _Wisdom in Small Doses_ | Ben Finney -- http://mail.python.org/mailman/listinfo/python-list
Re: What makes an iterator an iterator?
On Wed, 18 Apr 2007 15:39:22 +1000, Steven D'Aprano wrote: > I thought that an iterator was any object that follows the iterator > protocol, that is, it has a next() method and an __iter__() method. ... > class Parrot(object): ... > def __init__(self): > self.next = self._next() self.next isn't a method here, it's a generator. You could do: def __init__(self): self.next = self._next().next But, having tested, that doesn't appear to work either - I think this is because, again, self.next is not strictly a method, it's an attribute that happens to be callable. The python manual gives you a possible solution: ---QUOTE http://docs.python.org/lib/typeiter.html --- Python's generators provide a convenient way to implement the iterator protocol. If a container object's __iter__() method is implemented as a generator, it will automatically return an iterator object (technically, a generator object) supplying the __iter__() and next() methods. ---END QUOTE--- i.e., just rename your _next function to __iter__ . Your class won't itself be an iterator, but it will be usable in for statements and so one, and convertable to an iterator with the iter builtin. -- http://mail.python.org/mailman/listinfo/python-list
What makes an iterator an iterator?
I thought that an iterator was any object that follows the iterator protocol, that is, it has a next() method and an __iter__() method. But I'm having problems writing a class that acts as an iterator. I have: class Parrot(object): def __iter__(self): return self def __init__(self): self.next = self._next() def _next(self): for word in "Norwegian Blue's have beautiful plumage!".split(): yield word But this is what I get: >>> P = Parrot() >>> for word in P: ... print word ... Traceback (most recent call last): File "", line 1, in TypeError: iter() returned non-iterator of type 'Parrot' Why is my instance not an iterator? But I can do this: >>> for word in P.next: ... print word ... Norwegian Blue's have beautiful plumage! I find myself perplexed as to this behaviour. -- Steven D'Aprano -- http://mail.python.org/mailman/listinfo/python-list