TIME NOW
World current time now,
CALENDAR
Calendar monthly, yearly
login CONVERT LENGTH
login CONVERT TEMPERATURE
login DICTIONARIES, LISTS
login SCIENCE EDUCATION RELIGION
login WORK CALCULATOR
login CALCULATE LIFE

Python 3 programming language, learn python, tutorial

Previous articlePage bottomNext article  ALL TOPICS

Python 3. Iterators, generators. yeld

 To go over a group of items, that is iteration.

An iterable is an object that has an __iter__ method which returns an iterator, or which defines a  __getitem__ method that can take sequential indexes starting from zero (and raises an IndexError when the indexes are no longer valid). So an iterable is an object that you can get an iterator from.

An iterator is an object with a next (Python 2) or __next__ (Python 3) method.

1. The for statement calls iter() on the container object. The function returns an iterator object that defines the method __next__() which accesses elements in the container one at a time. When there are no more elements, __next__() raises a StopIteration exception which tells the for loop to terminate. You can call the __next__() method using the next() built-in function:
s = 'abc'
it = iter(s)
print(it)

print(next(it))
print(next(it))
print(next(it))
print(next(it))

1a.

# As you can see, in the first case foo holds the entire list in memory at once. It's not a big deal for a list with 5 elements, but what if you want a list of 5 million?

def get_odd_numbers(i):
    return range(1, i, 2)
    
def yield_odd_numbers(i):
    for x in range(1, i, 2):
       yield x
       
foo = get_odd_numbers(10)
bar = yield_odd_numbers(10)
print (foo)

print(bar)
# saves, remembers state of continuation
print(bar.next())
print(bar.next())
print(bar.next())

2.
class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)

    def __iter__(self):
        return self

    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]

rev = Reverse('spam')
print (iter(rev))

for char in rev:
    print(char)

3.
class Counter:
    def __init__(self, low, high):
        self.current = low
        self.high = high

    def __iter__(self):
        return self

    def __next__(self):
        if self.current > self.high:
            raise StopIteration
        else:
            self.current += 1
            return self.current - 1

for c in Counter(3, 8):
    print (c)

ITERABLES

3a.
When you create a list, you can read its items one by one. Reading its items one by one is called iteration:
mylist = [1, 2, 3]
for i in mylist:
    print(i)

3b.
mylist is an iterable. When you use a list comprehension, you create a list, and so an iterable:
mylist = [x*x for x in range(3)]
for i in mylist:
   print(i)

   
Everything you can use "for... in..." on is an iterable; lists, strings, files...

These iterables are handy because you can read them as much as you wish, but you store all the values in memory and this is not always what you want when you have a lot of values.
GENERATORS

4. Generators are iterators, a kind of iterable you can only iterate over once. Generators do not store all the values in memory, they generate the values on the fly:
mygenerator = (x*x for x in range(3))

for i in mygenerator:
    print(i)

for i in mygenerator:
    print(i)

It is just the same except you used () instead of []. BUT, you cannot perform for i in mygenerator a second time since generators can only be used once: they calculate 0, then forget about it and calculate 1, and end calculating 4, one by one.

yield is a keyword that is used like return, except the function will return a generator. To master yield, you must understand that when you call the function, the code you have written in the function body does not run. The function only returns the generator object, this is a bit tricky. Then, your code will be run each time the for uses the generator. The generator object is sort of like an adapter - at one end it exhibits the iterator protocol, by exposing __iter__() and next() methods to keep the for loop happy. At the other end however, it runs the function just enough to get the next value out of it, and puts it back in suspended mode. A generator is a lazy, incrementally-pending list, and yield statements allow you to use function notation to program the list values the generator should incrementally spit out. NOTE: the generator is NOT a normal function, it remembers previous state like local variables (stack),
https://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do

4a.
def makeRange(n):
    # return 0,1,2,...,n-1
    i = 0
    while i < n:
        yield i
        i += 1

print (makeRange(5))

# To force the generator to immediately return its pending values, you can pass it into list() (just like you could any iterable):
print (list(makeRange(5)))

4b.
def makeRange(n):
    # return 0,1,2,...,n-1
    i = 0
    while i < n:
        yield i
        i += 1

x = makeRange(6)
print (list(x))

# cleared
print (list(x))

4. Many yield:
def f():
   yield 1
   yield 2
   yield 3
 
g = f()
for i in g:
   print (i)

for i in g:
   print (i)

5.
def createGenerator():
    mylist = range(3)
    for i in mylist:
        yield i*i
        
# create a generator
mygenerator = createGenerator()

# mygenerator is an object!
print(mygenerator)

for i in mygenerator:
    print(i)

# nothing
for i in mygenerator:
    print(i)

6.
def counter(low, high):
    current = low
    while current <= high:
        yield current
        current += 1

for c in counter(3, 8):
    print (c)

7.
def some_function():
    i = 1    
    yield i

for i in some_function():
    print (i)

8.
def some_function():

    i = [1,2,3]    
    yield i

for i in some_function():
    print (i)

9.
def some_function():
    for i in range(4):
        yield i

for i in some_function():
    print (i)


10. infinite generator
# infinite
def f():
  while True:
    yield 4

# not infinite
def g():
  yield 4

# call infinite
y = 0
for i in f():
  y = y + 1;
  if (y > 5):
    break
  print ("f = ", i)
 
# call not infinite
y = 0
for i in g():
  y = y + 1;
  if (y > 5):
    break
  print ("g = ", i)
 
 
-- 
Previous articlePage topNext article  ALL TOPICS



 Use username: Guest, Anonymous, Programmer






QUOTES:
I have given up reading books; I find it takes my mind off myself.
Oscar Levant
A thousand years may scare form a state. An hour may lay it in ruins.
Lord Byron
Many people take no care of their money till they come nearly to the end of it, and others do just the same with their time.
Johann Wolfgang Von Goethe