Iteration:

  • Iteration is a general term for taking each item of something, one after another. Any time you use a loop, explicit or implicit, to go over a group of items, that is iteration.
  • Code with Comments:
# Iteration Example
num = [1, 2, 3]

# Using a for loop to iterate over each item in the list
for i in num:
    print(i)
  • Explanation:
    • The for loop iterates through each element (i) in the list num and prints each element.

Iterator:

  • An Iterator is an object that allows the programmer to traverse through a sequence of data without having to store the entire data in the memory.
  • Code with Comments:
# Iterator Example
L = [x for x in range(1, 10000)]

# Calculate and print the memory size of the list divided by 64
import sys
print(sys.getsizeof(L) / 64)

# Creating an iterator for a large range and printing its memory size divided by 64
x = range(1, 10000000000)
print(sys.getsizeof(x) / 64)
  • Explanation:
    • The code creates an iterator L using list comprehension and calculates its memory size.
    • It then demonstrates the memory efficiency of iterators by creating a large range (x) iterator and printing its memory size.

Iterable:

  • An iterable is an object that can be iterated over, generating an iterator when passed to the iter() method.
  • Code with Comments:
# Iterable Example
L = [1, 2, 3]

# Checking the type of L (it is an iterable)
type(L)

# Checking the type of iter(L) (it is an iterator)
type(iter(L))
  • Explanation:
    • This code confirms that a list L is an iterable, and calling iter(L) generates an iterator.

Point to remember

  • Every Iterator is also and Iterable
  • Not all Iterables are Iterators

Trick

  • Every Iterable has an iter function
  • Every Iterator has both iter function as well as a next function

Custom For Loop:

  • Demonstrates a custom for loop function that manually iterates through any iterable object.
  • Code with Comments:
# Custom for loop function
def my_for_loop(iterable):
    iterator = iter(iterable)
    
    # Continue looping until StopIteration is raised
    while True:
        try:
            print(next(iterator))
        except StopIteration:
            break

a = [1, 2, 3]
my_for_loop(a)
  • Explanation:
    • This section defines a custom for loop function that manually iterates through any iterable using next() and handles StopIteration to break the loop.

Confusing Point about Iterators:

  • Highlights the shared memory address when creating a new iterator from an existing iterator.
  • Code with Comments:
# A Confusing Point
num = [1, 2, 3]
iter_obj = iter(num)

# Printing the memory address of the first iterator
print(id(iter_obj), 'Address of iterator 1')

# Creating a second iterator from the first iterator and printing its address
iter_obj2 = iter(iter_obj)
print(id(iter_obj2), 'Address of iterator 2')
  • Explanation:
    • This part highlights that creating a new iterator (iter_obj2) from an existing iterator (iter_obj) results in both iterators sharing the same memory address.

Custom range() Function:

  • Defines a custom range-like class and its iterator to mimic the behavior of the built-in range() function.
  • Code with Comments:
# Custom range() function
class my_range:
    def __init__(self, start, end):
        self.start = start
        self.end = end
        
    def __iter__(self):
        return my_range_iterator(self)

class my_range_iterator:
    def __init__(self, iterable_obj):
        self.iterable = iterable_obj
    
    def __iter__(self):
        return self
    
    def __next__(self):
        # Stop iteration if the start is greater than or equal to the end
        if self.iterable.start >= self.iterable.end:
            raise StopIteration
        
        # Return the current value and increment the start
        current = self.iterable.start
        self.iterable.start += 1
        return current

# Creating an instance of the custom range class
x = my_range(1, 11)
type(x)  # Checking the type of x (it is an instance of my_range)
iter(x)  # Obtaining an iterator from x
  • Explanation:
    • This section defines a custom my_range class and its iterator, mimicking the behavior of the built-in range() function. It demonstrates creating an instance of the class and obtaining an iterator from it.

16 Replies to “python iterators and iterables”

Leave a Reply

Your email address will not be published. Required fields are marked *