__iter__ see for more on yield and generators if this is puzzlingand compare it with the more explicit __next__ version in squares py earlier you'll notice that this new squares_yield py version is lines shorter ( versus in sensethis scheme reduces class coding requirements much like the closure functions of but in this case does so with combination of functional and oop techniquesinstead of an alternative to classes for examplethe generator method still leverages self attributes this may also very well seem like one too many levels of magic to some observers--it relies on both the iteration protocol and the object creation of generatorsboth of which are highly implicit (in contradiction of longstanding python themessee import thisopinions asideit' important to understand the non-yield flavor of class iterables toobecause it' explicitgeneraland sometimes broader in scope stillthe __iter__/yield technique may prove effective in cases where it applies it also comes with substantial advantage--as the next section explains multiple iterators with yield besides its code concisenessthe user-defined class iterable of the prior section based upon the __iter__/yield combination has an important added bonus--it also supports multiple active iterators automatically this naturally follows from the fact that each call to __iter__ is call to generator functionwhich returns new generator with its own copy of the local scope for state retentionpython from squares_yield import squares squares( iter(snext( )next( iter(snext( next( using the __iter__/yield squares with yieldmultiple iterators automatic is independent of jown local state although generator functions are single-scan iterablesthe implicit calls to __iter__ in iteration contexts make new generators supporting new independent scanss squares( for in seach for calls __iter__ for in sprint('% :% (ij)end=' : : : : : : : : : operator overloading