Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.001 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'received:209.85.223': 0.03; 'explicitly': 0.05; 'desired.': 0.07; 'explicit': 0.07; 'referring': 0.07; 'expression:': 0.09; 'filter,': 0.09; 'grid': 0.09; 'immutable': 0.09; 'rows': 0.09; 'cc:addr:python-list': 0.11; 'def': 0.12; 'itself.': 0.14; 'charles': 0.16; 'col': 0.16; 'constructs': 0.16; 'fine.': 0.16; 'from:addr:rosuav': 0.16; 'from:name:chris angelico': 0.16; 'guessing': 0.16; 'happily': 0.16; 'iterable': 0.16; 'iterator': 0.16; 'iterator,': 0.16; 'object).': 0.16; 'subclass': 0.16; 'wrote:': 0.18; 'things.': 0.19; 'value.': 0.19; 'feb': 0.22; 'cc:addr:python.org': 0.22; 'cell:': 0.24; "shouldn't": 0.24; 'cc:2**0': 0.24; 'source': 0.25; 'define': 0.26; 'this:': 0.26; 'header:In-Reply-To:1': 0.27; 'function': 0.29; 'raise': 0.29; 'message-id:@mail.gmail.com': 0.30; "i'm": 0.30; 'code': 0.31; 'object.': 0.31; 'slot': 0.31; 'trivial': 0.31; 'yes.': 0.31; 'class': 0.32; '(e.g.': 0.33; 'skip:_ 10': 0.34; 'received:209.85': 0.35; 'classes': 0.35; 'something': 0.35; 'but': 0.35; 'received:google.com': 0.35; 'version': 0.36; 'are,': 0.36; 'yield': 0.36; 'next': 0.36; 'method': 0.36; 'should': 0.36; 'received:209': 0.37; 'implement': 0.38; 'easiest': 0.38; 'fact': 0.38; 'pm,': 0.38; 'remove': 0.60; 'skip:u 10': 0.60; 'easy': 0.60; 'new': 0.61; 'range': 0.61; 'simply': 0.61; "you're": 0.61; 'you.': 0.62; 'within': 0.65; 'determine': 0.67; 'apart': 0.72; 'cut': 0.74; '2015': 0.84; 'subject:skip:S 10': 0.84; 'to:none': 0.92 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:cc :content-type; bh=oCzh/TEUFwkWC6XFW8kxyKD/XR73rVG6uLLCnSi6MtQ=; b=J54tp0776DWzDRUGxSWwknp/PKcbHd196zkUbm+bUcZm3geVuoA7YUwn0IMnQtT/lB lRBdVHGQ5MUji8z2uF95Lp/7+j4SNLgO7QUoUfMhU2vgn54lnQ4orvUeFyfrelb/HDvk H6x6RiqILloK9m0Bf4QmmL5xlXmsnzsp8dGYMeUFlW4lRto9tbVAkeFGxw47pLorZ4KB NpwmmiSDUfVlC2dOQoRd8VmfSum9uf1tByqE1ZMwFyxQZNXqLjwB0kfyOLzzt/Xaw4qK Fl9GAndGhdQo4yhB+1eYwpxQLkOXDTR5rMoS+4NBdhiOCWJJc045NxCfAgfL0zhAg2Nx YnIA== MIME-Version: 1.0 X-Received: by 10.50.79.161 with SMTP id k1mr21134044igx.14.1423543585649; Mon, 09 Feb 2015 20:46:25 -0800 (PST) In-Reply-To: <54D98A35.9060203@earthlink.net> References: <54d94307$0$12998$c3e8da3$5496439d@news.astraweb.com> <54D98A35.9060203@earthlink.net> Date: Tue, 10 Feb 2015 15:46:25 +1100 Subject: Re: __next__ and StopIteration From: Chris Angelico Cc: "python-list@python.org" Content-Type: text/plain; charset=UTF-8 X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 59 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1423543595 news.xs4all.nl 2893 [2001:888:2000:d::a6]:39212 X-Complaints-To: abuse@xs4all.nl Path: csiph.com!usenet.pasdenom.info!bete-des-vosges.org!feed.ac-versailles.fr!nerim.net!novso.com!newsfeed.xs4all.nl!newsfeed4.news.xs4all.nl!xs4all!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail Xref: csiph.com comp.lang.python:85425 On Tue, Feb 10, 2015 at 3:33 PM, Charles Hixson wrote: >> The proper version of the "hard way" is: >> >> 1) The __iter__ method of the iterable constructs a new iterator >> instance and returns it. >> >> 2) The __iter__ method of the *iterator* simply returns itself. >> >> 3) The __next__ method of the iterator tracks the current value and >> returns the next value. Note that the iterator should never store the >> iterable's data internally, unless the iterable is immutable and the >> calculation is trivial (e.g. a range object). Instead, it should >> determine the next value by referring to its source iterable. > > So if I'm understanding this correctly, I should implement as an internal > class within Grid something like: > class GridIter(Iterator): Apart from the fact that you shouldn't have to explicitly subclass Iterator, yes. But this is the hard way to do things. The easy way is to simply define an __iter__ method on your Grid which returns an iterator - and one excellent form of iterator, for custom classes like this, is a generator object. Your original code can slot happily in, with one tiny change: class Grid: blah blah def __iter__(self): for row in range(self._rows): for col in range(self._cols): if self._grid[row][col]: yield self._grid[row][col] The only change is to remove the explicit StopIteration at the end; once your generator function terminates, the generator object will raise StopIteration forever afterward, without any help from you. (Also, post-PEP479, the explicit raise will actually cause RuntimeError, so it's not just superfluous, but actually a problem.) But I'm guessing that your grid and rows are actually iterable themselves. If they are, you can cut the code down to this: def __iter__(self): for row in self._grid: for cell in row: if cell: yield cell or a generator expression: def __iter__(self): return (cell for row in self._grid for cell in row if cell) or itertools.chain and filter, if you so desired. As long as you return an iterator, you're fine. This is far and away the easiest way to make a class iterable. ChrisA