0% found this document useful (0 votes)
22 views

Python Unit 5-1

The document discusses Python iterators and how they work. It explains that iterators are objects that can be used to iterate over iterable objects like lists, tuples, strings and custom iterator classes. It provides examples of using built-in iterators with for loops and by calling next() directly. It also demonstrates how to create a custom iterator class that implements the iterator protocol.

Uploaded by

Rahul Bhati
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
22 views

Python Unit 5-1

The document discusses Python iterators and how they work. It explains that iterators are objects that can be used to iterate over iterable objects like lists, tuples, strings and custom iterator classes. It provides examples of using built-in iterators with for loops and by calling next() directly. It also demonstrates how to create a custom iterator class that implements the iterator protocol.

Uploaded by

Rahul Bhati
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 18

Unit 5

Python Iterators
An iterator is an object that contains a countable number of values. An iterator is an object that
can be iterated upon, meaning that you can traverse through all the values.

Iterators are everywhere in Python. They are elegantly implemented within for loops,
comprehensions, generators etc. but hidden in plain sight. Iterator in Python is simply
an object that can be iterated upon. An object which will return data, one element at a time.

Technically speaking, Python iterator object must implement two special


methods, __iter__() and __next__(), collectively called the iterator protocol.
An object is called iterable if we can get an iterator from it. Most of built-in containers in
Python like: list, tuple, string etc. are iterables.
The iter() function (which in turn calls the __iter__() method) returns an iterator from them.

Iterator vs Iterable
Lists, tuples, dictionaries, and sets are all iterable objects. They are iterable containers which you
can get an iterator from. All these objects have a iter() method which is used to get an iterator:

Example

Return an iterator from a tuple, and print each value:

mytuple = ("apple", "banana", "cherry")


myit = iter(mytuple)

print(next(myit))
print(next(myit))
print(next(myit))

Even strings are iterable objects, and can return an iterator:

Example

Strings are also iterable objects, containing a sequence of characters:

mystr = "banana"
myit = iter(mystr)

print(next(myit))
print(next(myit))
print(next(myit))
print(next(myit))
print(next(myit))
print(next(myit))

Looping Through an Iterator


We can also use a for loop to iterate through an iterable object:

Example

Iterate the values of a tuple:

mytuple = ("apple", "banana", "cherry")

for x in mytuple:
print(x)

Example

Iterate the characters of a string:

mystr = "Rakesh"

for x in mystr:
print(x)

The for loop actually creates an iterator object and executes the next() method for each loop.

Create an Iterator

To create an object/class as an iterator you have to implement the


methods __iter__() and __next__() to your object. The __iter__() method acts similar, you can
do operations (initializing etc.), but must always return the iterator object itself.

The __next__() method also allows you to do operations, and must return the next item in the
sequence.

Example

Create an iterator that returns numbers, starting with 1, and each sequence will increase by one
(returning 1,2,3,4,5 etc.):

class MyNumbers:
def __iter__(self):
self.a = 1
return self

def __next__(self):
x = self.a
self.a += 1
return x

myclass = MyNumbers()
myiter = iter(myclass)

print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))

Stop Iteration

The example above would continue forever if you had enough next() statements, or if it was used
in a for loop. To prevent the iteration to go on forever, we can use the StopIteration statement.

In the __next__() method, we can add a terminating condition to raise an error if the iteration is
done a specified number of times:

Example

Stop after 20 iterations:

class MyNumbers:
def __iter__(self):
self.a = 1
return self

def __next__(self):
if self.a <= 20:
x = self.a
self.a += 1
return x
else:
raise StopIteration

myclass = MyNumbers()
myiter = iter(myclass)
for x in myiter:
print(x)

Recursion in Python
A function that calls itself is a recursive function. This method is used when a certain problem is
defined in terms of itself. Although this involves iteration, using an iterative approach to solve
such a problem can be tedious. The recursive approach provides a very concise solution to a
seemingly complex problem. It looks glamorous but can be difficult to comprehend!
The most popular example of recursion is the calculation of the factorial. Mathematically the
factorial is defined as: n! = n * (n-1)!

We use the factorial itself to define the factorial. Hence, this is a suitable case to write a recursive
function. Let us expand the above definition for the calculation of the factorial value of 5.

5! = 5 X 4!
5 X4 X 3!
5 X4 X 3 X 2!
5 X4 X 3 X 2 X 1!
5 X4 X 3 X 2 X 1
= 120

While we can perform this calculation using a loop, its recursive function involves successively
calling it by decrementing the number until it reaches 1. The following is a recursive function to
calculate the factorial.

Example: Recursive Function


def factorial(n):
if n == 1:
print(n)
return 1
else:
print (n,'*', end=' ')
return n * factorial(n-1)

The above recursive function can be called as below.

>>> factorial(5)

5*4*3*2*1

120
When the factorial function is called with 5 as argument, successive calls to the same function
are placed, while reducing the value of 5. Functions start returning to their earlier call after the
argument reaches 1. The return value of the first call is a cumulative product of the return values
of all calls.

Python Program for Fibonacci numbers


The Fibonacci numbers are the numbers in the following integer sequence.
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ……..
In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence
relation

Fn = Fn-1 + Fn-2
with seed values
F0 = 0 and F1 = 1.

Method 1 ( Use recursion ) :


# Function for nth Fibonacci number

def Fibonacci(n):
if n<0:
print("Incorrect input")
# First Fibonacci number is 0
elif n==1:
return 0
# Second Fibonacci number is 1
elif n==2:
return 1
else:
return Fibonacci(n-1)+Fibonacci(n-2)
# Driver Program
print(Fibonacci(9))
Output:
21

Method 3 ( Space Optimized):

# Function for nth fibonacci number - Space Optimisataion


# Taking 1st two fibonacci numbers as 0 and 1

def fibonacci(n):
a=0
b=1
if n < 0:
print("Incorrect input")
elif n == 0:
return a
elif n == 1:
return b
else:
for i in range(2,n):
c=a+b
a=b
b=c
return b

# Driver Program

print(fibonacci(9))

Output:
21

Tower of Hanoi
It is a mathematical puzzle where we have three rods and n disks. The objective of the puzzle is
to move the entire stack to another rod, obeying the following simple rules:
1) Only one disk can be moved at a time.
2) Each move consists of taking the upper disk from one of the stacks and placing it on top of
another stack i.e. a disk can only be moved if it is the uppermost disk on a stack.
3) No disk may be placed on top of a smaller disk.
Approach :
Take an example for 2 disks :
Let rod 1 = 'A', rod 2 = 'B', rod 3 = 'C'.
Step 1 : Shift first disk from 'A' to 'B'.
Step 2 : Shift second disk from 'A' to 'C'.
Step 3 : Shift first disk from 'B' to 'C'.
The pattern here is :
Shift 'n-1' disks from 'A' to 'B'.
Shift last disk from 'A' to 'C'.
Shift 'n-1' disks from 'B' to 'C'.

Image illustration for 3 disks :


Examples:
Input : 2
Output : Disk 1 moved from A to B
Disk 2 moved from A to C
Disk 1 moved from B to C
Input : 3
Output : Disk 1 moved from A to C
Disk 2 moved from A to B
Disk 1 moved from C to B
Disk 3 moved from A to C
Disk 1 moved from B to A
Disk 2 moved from B to C
Disk 1 moved from A to C
# Recursive Python function to solve tower of hanoi

def TowerOfHanoi(n , from_rod, to_rod, aux_rod):


if n == 1:
print "Move disk 1 from rod",from_rod,"to rod",to_rod
return
TowerOfHanoi(n-1, from_rod, aux_rod, to_rod)
print "Move disk",n,"from rod",from_rod,"to rod",to_rod
TowerOfHanoi(n-1, aux_rod, to_rod, from_rod)

# Driver code
n=4
TowerOfHanoi(n, 'A', 'C', 'B')
# A, C, B are the name of rods

Output:
Move disk 1 from rod A to rod B
Move disk 2 from rod A to rod C
Move disk 1 from rod B to rod C
Move disk 3 from rod A to rod B
Move disk 1 from rod C to rod A
Move disk 2 from rod C to rod B
Move disk 1 from rod A to rod B
Move disk 4 from rod A to rod C
Move disk 1 from rod B to rod C
Move disk 2 from rod B to rod A
Move disk 1 from rod C to rod A
Move disk 3 from rod B to rod C
Move disk 1 from rod A to rod B
Move disk 2 from rod A to rod C
Move disk 1 from rod B to rod C

Python Arrays
An array is a collection of items stored at contiguous memory locations. The idea is to store
multiple items of the same type together. This makes it easier to calculate the position of each
element by simply adding an offset to a base value, i.e., the memory location of the first element
of the array (generally denoted by the name of the array).

Creating a Array

Array in Python can be created by importing array module. array(data_type, value_list) is used
to create an array with data type and value list specified in its arguments.
# Python program to demonstrate creation of Array

# importing "array" for array creations

import array as arr

# creating an array with integer type


a = arr.array('i', [1, 2, 3])

# printing original array


print ("The new created array is : ", end =" ")
for i in range (0, 3):
print (a[i], end =" ")
print()

# creating an array with float type


b = arr.array('d', [2.5, 3.2, 3.3])

# printing original array


print ("The new created array is : ", end =" ")
for i in range (0, 3):
print (b[i], end =" ")

Output :
The new created array is : 1 2 3
The new created array is : 2.5 3.2 3.3

Adding Elements to a Array

Elements can be added to the Array by using built-in insert() function. Insert is used to insert one
or more data elements into an array. Based on the requirement, a new element can be added at
the beginning, end, or any given index of array. append() is also used to add the value mentioned
in its arguments at the end of the array.

# Python program to demonstrate Adding Elements to a Array

# importing "array" for array creations

import array as arr

# array with int type


a = arr.array('i', [1, 2, 3])
print ("Array before insertion : ", end =" ")
for i in range (0, 3):
print (a[i], end =" ")
print()

# inserting array using


# insert() function
a.insert(1, 4)

print ("Array after insertion : ", end =" ")


for i in (a):
print (i, end =" ")
print()

# array with float type


b = arr.array('d', [2.5, 3.2, 3.3])

print ("Array before insertion : ", end =" ")


for i in range (0, 3):
print (b[i], end =" ")
print()

# adding an element using append()


b.append(4.4)

print ("Array after insertion : ", end =" ")


for i in (b):
print (i, end =" ")
print()

Output :

Array before insertion : 1 2 3


Array after insertion : 1 4 2 3
Array before insertion : 2.5 3.2 3.3
Array after insertion : 2.5 3.2 3.3 4.4
Accessing elements from the Array

In order to access the array items refer to the index number. Use the index operator [ ] to access
an item in a array. The index must be an integer.

# Python program to demonstrate accessing of element from list

# importing array module


import array as arr

# array with int type


a = arr.array('i', [1, 2, 3, 4, 5, 6])

# accessing element of array


print("Access element is: ", a[0])

# accessing element of array


print("Access element is: ", a[3])

# array with float type


b = arr.array('d', [2.5, 3.2, 3.3])

# accessing element of array


print("Access element is: ", b[1])

# accessing element of array


print("Access element is: ", b[2])
Output :
Access element is: 1
Access element is: 4
Access element is: 3.2
Access element is: 3.3

Removing Elements from the Array

Elements can be removed from the array by using built-in remove() function but an Error arises
if element doesn’t exist in the set. Remove() method only removes one element at a time, to
remove range of elements, iterator is used.

pop() function can also be used to remove and return an element from the array, but by default it
removes only the last element of the array, to remove element from a specific position of the
array, index of the element is passed as an argument to the pop() method.

Note – Remove method in List will only remove the first occurrence of the searched element.

# Python program to demonstrate Removal of elements in a Array

# importing "array" for array operations

import array
# initializing array with array values
# initializes array with signed integers
arr = array.array('i', [1, 2, 3, 1, 5])

# printing original array


print ("The new created array is : ", end ="")
for i in range (0, 5):
print (arr[i], end =" ")

print ("\r")

# using pop() to remove element at 2nd position


print ("The popped element is : ", end ="")
print (arr.pop(2))

# printing array after popping


print ("The array after popping is : ", end ="")
for i in range (0, 4):
print (arr[i], end =" ")

print("\r")

# using remove() to remove 1st occurrence of 1


arr.remove(1)

# printing array after removing


print ("The array after removing is : ", end ="")
for i in range (0, 3):
print (arr[i], end =" ")
Output:
The new created array is : 1 2 3 1 5
The popped element is : 3
The array after popping is : 1 2 1 5
The array after removing is : 2 1 5

Slicing of a Array

In Python array, there are multiple ways to print the whole array with all the elements, but to
print a specific range of elements from the array, we use Slice operation. Slice operation is
performed on array with the use of colon(:). To print elements from beginning to a range use
[:Index], to print elements from end use [:-Index], to print elements from specific Index till the
end use [Index:], to print elements within a range, use [Start Index:End Index] and to print whole
List with the use of slicing operation, use [:]. Further, to print whole array in reverse order, use
[::-1].

# Python program to demonstrate slicing of elements in a Array

# importing array module

import array as arr

# creating a list
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

a = arr.array('i', l)
print("Intial Array: ")
for i in (a):
print(i, end =" ")

# Print elements of a range


# using Slice operation
Sliced_array = a[3:8]
print("\nSlicing elements in a range 3-8: ")
print(Sliced_array)

# Print elements from a


# pre-defined point to end
Sliced_array = a[5:]
print("\nElements sliced from 5th "
"element till the end: ")
print(Sliced_array)
# Printing elements from
# beginning till end
Sliced_array = a[:]
print("\nPrinting all elements using slice operation: ")
print(Sliced_array)
Output :

Intial Array:
1 2 3 4 5 6 7 8 9 10
Slicing elements in a range 3-8:
array('i', [4, 5, 6, 7, 8])

Elements sliced from 5th element till the end:


array('i', [6, 7, 8, 9, 10])

Printing all elements using slice operation:


array('i', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

Searching element in a Array

In order to search an element in the array we use a python in-built index() method. This function
returns the index of the first occurrence of value mentioned in arguments.

# Python code to demonstrate searching an element in array

# importing array module


import array

# initializing array with array values


# initializes array with signed integers
arr = array.array('i', [1, 2, 3, 1, 2, 5])

# printing original array


print ("The new created array is : ", end ="")
for i in range (0, 6):
print (arr[i], end =" ")

print ("\r")

# using index() to print index of 1st occurrenece of 2


print ("The index of 1st occurrence of 2 is : ", end ="")
print (arr.index(2))

# using index() to print index of 1st occurrenece of 1


print ("The index of 1st occurrence of 1 is : ", end ="")
print (arr.index(1))
Output:
The new created array is : 1 2 3 1 2 5
The index of 1st occurrence of 2 is : 1
The index of 1st occurrence of 1 is : 0

Updating Elements in a Array

In order to update an element in the array we simply reassign a new value to the desired index
we want to update.
# Python code to demonstrate how to update an element in array

# importing array module

import array

# initializing array with array values


# initializes array with signed integers
arr = array.array('i', [1, 2, 3, 1, 2, 5])

# printing original array


print ("Array before updation : ", end ="")
for i in range (0, 6):
print (arr[i], end =" ")

print ("\r")

# updating a element in a array


arr[2] = 6
print("Array after updation : ", end ="")
for i in range (0, 6):
print (arr[i], end =" ")
print()

# updating a element in a array


arr[4] = 8
print("Array after updation : ", end ="")
for i in range (0, 6):
print (arr[i], end =" ")

Output:

Array before updation : 1 2 3 1 2 5


Array after updation : 1 2 6 1 2 5
Array after updation : 1 2 6 1 8 5

Stack in Python
A stack is a linear data structure that stores items in a Last-In/First-Out (LIFO) or First-In/Last-
Out (FILO) manner. In stack, a new element is added at one end and an element is removed from
that end only. The insert and delete operations are often called push and pop.

The functions associated with stack are:


• empty() – Returns whether the stack is empty – Time Complexity : O(1)
• size() – Returns the size of the stack – Time Complexity : O(1)
• top() – Returns a reference to the top most element of the stack – Time Complexity : O(1)
• push(g) – Adds the element ‘g’ at the top of the stack – Time Complexity : O(1)
• pop() – Deletes the top most element of the stack – Time Complexity : O(1)

Implementation

There are various ways from which a stack can be implemented in Python. This article covers the
implementation of stack using data structures and modules from Python library.
Stack in Python can be implemented using following ways:
• list

Implementation using list

Python’s built-in data structure list can be used as a stack. Instead of push(), append() is used to
add elements to the top of stack while pop() removes the element in LIFO order.
Unfortunately, list has a few shortcomings. The biggest issue is that it can run into speed issue as
it grows. The items in list are stored next to each other in memory, if the stack grows bigger than
the block of memory that currently hold it, then Python needs to do some memory allocations.
This can lead to some append() calls taking much longer than other ones.

# Python program to demonstrate stack implementation using list

stack = []

# append() function to push


# element in the stack
stack.append('a')
stack.append('b')
stack.append('c')

print('Initial stack')
print(stack)

# pop() fucntion to pop


# element from stack in
# LIFO order
print('\nElements poped from stack:')
print(stack.pop())
print(stack.pop())
print(stack.pop())

print('\nStack after elements are poped:')


print(stack)

# uncommenting print(stack.pop())
# will cause an IndexError
# as the stack is now empty
Output:
Initial stack
['a', 'b', 'c']

Elements poped from stack:


c
b
a
Stack after elements are poped:
[]
Traceback (most recent call last):
File "/home/2426bc32be6a59881fde0eec91247623.py", line 25, in <module>
print(stack.pop())
IndexError: pop from empty list

You might also like