for char in reverse('golf')print(charf anything that can be done with generators can also be done with class-based iterators as described in the previous section what makes generators so compact is that the __iter__(and __next__(methods are created automatically another key feature is that the local variables and execution state are automatically saved between calls this made the function easier to write and much more clear than an approach using instance variables like self index and self data in addition to automatic method creation and saving program statewhen generators terminatethey automatically raise stopiteration in combinationthese features make it easy to create iterators with no more effort than writing regular function generator expressions some simple generators can be coded succinctly as expressions using syntax similar to list comprehensions but with parentheses instead of square brackets these expressions are designed for situations where the generator is used right away by an enclosing function generator expressions are more compact but less versatile than full generator definitions and tend to be more memory friendly than equivalent list comprehensions examplessum( * for in range( ) xvec [ yvec [ sum( * for , in zip(xvecyvec) sum of squares dot product from math import pisin sine_table {xsin( *pi/ for in range( )unique_words set(word for line in page for word in line split()valedictorian max((student gpastudent namefor student in graduatesdata 'golflist(data[ifor in range(len(data)- - - )[' '' '' '' ' generator expressions