Python Programming Course

 1) Lecture 1

# Printing Hello world
print ("Hello world")

# Addition
a = 100
b = 100
c = a + b
print (c)
print (200+500)

# Substraction
a = 100
b = 100
c = a - b
print (c)

# Multiplication
a = 100
b = 100
c = a * b
print (c)

print ("so the sum of {} and {} is {}".format(a,b,c))

2) Python Variables and Constants 

#declaring  and Assigning value to constants
PI = 3.14
GRAVITY = 9.8
print(PI)

#Declaring and assigning value to a variable
a = "Apple"
print(a)

#Changing value of a variable
a = "Aeroplane"
print(a)

a = 100
print (a)

#Assigning Multiple values to a variables
b,c,d = 1, 2.5, "Hello"
print(b,c,d)

#Assigning same value to multiple variables
b = c = d = 5
print(b,c,d)

3) Python Class and Objects 

#Classes and Objects

class MyComplexNumber:
    #Constructor methods
    def __init__(self, real=0, imag=0):
        print("MyComplexNumber constructor executing...")
        self.real_part = real
        self.imaginary_part = imag

    def displayComplex(self):
        print(f"{self.real_part} + {self.imaginary_part}j")

#Create a new object of type MyComplexNumber class
cmplx1 = MyComplexNumber(40,50)

#Calling displayComplex() function
#Output :40 + 50j
cmplx1.displayComplex()

# Create another object of type MyComplexNumber class
# and create a new attribute 'new_attribute'
cmplx2 = MyComplexNumber(60,70)
cmplx2.new_attribute = 80

#Output:(60,70,80)
print((cmplx2.real_part, cmplx2.imaginary_part,cmplx2.new_attribute))

#but cmplx1 object doesn't have attribute 'new_attribute
print(cmplx1)
del cmplx1.real_part
del cmplx1

4)Python Array Implementation

#python Array implimentation

#Defining and declaring  and Arrays
arr = [10,20,30,40,50]
print(arr)

#Accessing elements of array
print(arr[0])
print(arr[1])
print(arr[2])
print(arr[-1]) #Negative Indexing
print(arr[-2]) #Negative Indexing


brands = ["Coke", "Apple", "Google", "Microsoft","Toyota"]
print(brands)

#Finding the length of an array
num_of_brands = len(brands)
print(num_of_brands)

#Adding an element to an array using append()
brands.append("intel")
print(brands)

#Removing elements of an array using indexing
fruits = ["Apple","Banana","Mango","Grapes","Orange"]
fruits[1] = "Pineapple"
fruits[-1] = "Guava"
print(fruits)

#Removing elements from an array
colors = ["violet","indigo","blue","green","yellow","orange"]
print(colors)
del colors[4]
colors.remove("orange")
colors.pop(3)
print(colors)

#Concatenating two Arrays using the + operator
concat = [1,2,3]
print(concat)
concat + [4,5,6]
print(concat)
concat = concat + [4,5,6]
print(concat)

#Repeating/repetaing elements of an array
repeat = ["a"]
print(repeat)
repeat = repeat*5
print(repeat)

#Slicing of an array
sli = [1,2,3,4,5,6,7,8,9,10]
print(sli[2:5])
print(sli[:5])
print(sli[5:])
print(sli[:])

fruits = ["Apple","Banana","Mango","Grapes","Orange"]
print(fruits)
print(fruits[1:4])
print(fruits[ :3])
print(fruits[-4: ])
print(fruits[-3: -1])

#Declaring and defining=g multidimenional array
multd = [[1,2], [3,4],[5,6],[7,8]]
print(multd)
print(multd[0])
print(multd[3])
print(multd[2][1])
print(multd[3][0])

5) Python Keywords and Identifiers

#Python Keywords and Identifiers

#True False
print(5 == 5)
print(5 > 5)

#None
print(None == 0)
print(None == False)
print(None == [])
print(None == None)

def a_void_function():
    a = 1
    b = 2
    c = a + b

x = a_void_function()
print(x)

#and ,or,not
print(True and False)
print(True or False)
print(not False)

#as
import math as myMath
print(myMath.cos(myMath.pi))

#assert
assert 5 > 4
assert 5 == 5


#break
for i in range(11):
    if i == 5:
        break
    print(i)

#Continue
for i in range(1,8):
    if i == 5:
        continue
    print(i)

#Class
class ExampleClass:
    def function1(parameters):
        print("Function0() Executing... ")
    def function2(parameters):
        print("Function2() Executing... ")
ob1 = ExampleClass()
ob1.function1()
ob1.function2()

#def
def function_name(parameters):
    pass
function_name(10)

#del
# a = 10
# print(a)
# del a
# print(a)
# name 'a' is not defined


#if..elif..else
num = 2
if num == 1:
    print("One")
elif num == 2:
    print("Two")
else:
    print("something else..")

#try ..raise...catch...finally
try:
    x = 9
    raise ZeroDivisionError
except ZeroDivisionError:
    print("Division cannot be performed")
finally:
    print("Execution Successfully")

#for
for i in range(1,10):
    print(1)

#from .. import
import math
from math import cos
print(cos(10))
#global variable
globvar = 10
def read1():
    print(globvar)
def write1():
    global globvar
    globvar = 5
def write2():
    global globvar
    globvar = 15
read1()
write1()
read1()
write2()
read1()

#in
a = [1,2,3,4,5]
print(4 in a)
print(44 not in a)

#is
print(True is True)

# #lambda
# a = lambda X: x*2
# for i in range(1,6):
#     print(i, a(i), sep=":")

#nonlocal
def outer_function():
    a = 5
    def inner_function():
        nonlocal a
        a = 10
        print("Inner function:", a)
    inner_function()
    print("Outer function:", a)

outer_function()

#pass
def my_function(args):
    pass

#return
def func_return():
    a = 10
    return a
print(func_return())

#while
i = 5
while(i>0):
    print(i)
    i -= 1

#with
with open ('example.txt', 'w') as my_file:
    my_file.write("Hello, world!")

#yield
def my_generator():
    for i in range(6):
        yield i*i

g = my_generator()
for i in g:
    print(i)



6) Lecture 6) Python Tuples  lec 6 to 10 

#from .. import
import math
from math import cos
from os import PRIO_USER
print(cos(10))
#global variable
globvar = 10
def read1():
    print(globvar)
def write1():
    global globvar
    globvar = 5
def write2():
    global globvar
    globvar = 15
read1()
write1()
read1()
write2()
read1()

#in
a = [1,2,3,4,5]
print(4 in a)
print(44 not in a)

#is
print(True is True)

# #lambda
# a = lambda X: x*2
# for i in range(1,6):
#     print(i, a(i), sep=":")

#nonlocal
def outer_function():
    a = 5
    def inner_function():
        nonlocal a
        a = 10
        print("Inner function:", a)
    inner_function()
    print("Outer function:", a)

outer_function()

#pass
def my_function(args):
    pass

#return
def func_return():
    a = 10
    return a
print(func_return())

#while
i = 5
while(i>0):
    print(i)
    i -= 1

#with
with open ('example.txt', 'w') as my_file:
    my_file.write("Hello, world!")

#yield
def my_generator():
    for i in range(6):
        yield i*i

g = my_generator()
for i in g:
    print(i)









# lecture 7: python tuples
#creating an empty tuples
tuple1 = ()
print(tuple1)

#creating tuples with integer elements
tuple2 = (1, 2, 3, 4, 5)
print(tuple2)

# tuple with mixed datatypes
tuple3 = (101, "hello", 3332.14, "True")
print(tuple3)


#creation of nested tuples
tuple4 = ("points",[1, 2,3], (7,8,6))
print(tuple4)

# tuple can be created without any parentheses
# also called tuple packing
tuple5 = 101,"Anirban", 20000.0,"Hr Dept"
print(tuple5)

#tuple unpacking is also possible
empid, empname, empsal, empdept = tuple5
print(empid)
print(empname)
print(empsal)
print(empdept)

print(type(tuple5))





#accessing tuple elements
tuple1 = ('w','e','l','c','o','m','e')
print(tuple1)
print(tuple1[1])
print(tuple1[3])
print(tuple1[5])

# nested tuple
nest_tuple2 = ("points",(1, 2,3), [7,8,6])
print(nest_tuple2)
print(nest_tuple2[0][3])
print(nest_tuple2[1][2])
print(nest_tuple2[2][2])

#slicing tuple constants
tuple1 = ('w','e','l','c','o','m','e')
print(tuple1[1:3])

print(tuple1[:-3])

print(tuple1[3:])

print(tuple1[:])

#tuple elements are immutable
tuple1 = ('w','e','l','c','o','m','e')
print (tuple1)
#tuple1[2] = 'x' #error

# tuples can be reassigned
tuple1 = ('g','o','o','d','b','y','e')
print (tuple1)

#concatenation of tuples
tuple2 = ('w','e','l')
tuple3 = ('c','o','m','e')
print(tuple2)

# deletion operation an a tuple
tuple4 = ('w','e','l','c','o','m','e')

#as immutable so elements can not be deleted
# del tupl4[2]

#but can delete entire tuple
del tuple4


# tuple methods

tuple5 = ('w','e','l','c','o','m','e')
print(tuple5.count('e'))
print(tuple5.index('c'))


#tuple operations
tuple6 = ('w','e','l','c','o','m','e')

#membership
print('c' in tuple6)
print('c' not in tuple6)
print('a' in tuple6)
print('a' not in tuple6)

#iteration through tuple elements
tuple6 = ('w','e','l','c','o','m','e')
for letters in tuple6:
    print("letter is ->", letters)

#built-in functions with tuples
tuple7 = (22,33,55,44,77,66,11)
print(tuple7)

print(max(tuple7))
print(min(tuple7))
sorted_tuple = sorted(tuple7)
print(sorted_tuple)
print(tuple7)
print(len(tuple7))











# lecture 8: python sets

#Creating a sets
#set of integers
my_set1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
print(my_set1)

#set of mixed datatypes
my_set2 = {101, "Agnibha",(21,2,1994)}
print(my_set2)

#duplicate values are not allowed
my_set3 = {11,22,44,33,22}
print(my_set3)


# set connot have mutable items
# my_set4 = {1, 2, [3,4,5]}

# we can make set from a list
my_set5 = set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(my_set5)
print(type(my_set5))

# we can make list from a set
my_list1 = list({11,22,44,33})
print(my_list1)
print(type(my_list1))

#operations on sets
my_set1 = {11,33,44,66,55}
print(my_set1)

# 'set' object does not support indexing

# my_set1[0]

# add an element
my_set1.add(22)
print(my_set1)

#add multiple elements
my_set1.update([22,33,44])
print(my_set1)


# add list and set
my_set1.update([22,33,44], {55,66,77})
print(my_set1)


#remove and discard
#initialize my_set
my_set1 = {1, 2, 3, 4, 5}
print(my_set1)

#discart an element which is not present, no error
my_set1.discard(4)
print(my_set1)

#remove an element which is not present, error raised
my_set1.remove(1)
print(my_set1)

#discard an element which is present
my_set1.discard(3)
print(my_set1)


#set operations - union
myset1 = {0, 1, 2, 3, 4}
myset2 = {4, 5, 6, 7, 8}
print(myset1 | myset2)

#use / operator
print(myset1 & myset2)
print(myset1 ^ myset2)

#SET OPERATIONS and intersection
myset1 = {0, 1, 2, 3, 4}
myset2 = {4, 5, 6, 7, 8}
print(myset1)
print(myset2)

# set operations - symetric difference
myset1 = {0, 1, 2, 3, 4}
myset2 = {4, 5, 6, 7, 8}
print(myset1 - myset2)

# use ^ operator for symetric diference
print(myset1 ^ myset2)
print(myset1.symmetric_difference(myset2))


#set membership
myset1 = {0,1,2,3,4,5}
print(2 in myset1)
print(2 not in myset1)
print(6 in myset1)
print(6 not in myset1)

#iterating through a set
for letter in set("welcome"):
    print(letter)

# built-in functions with sets
myset1 = {0,1,2,3,4,5}
print(len(myset1))
print(max(myset1))
print(min(myset1))
print(sum(myset1))
print(sorted(myset1))

# python frozenset
#Fronzenset is a new class that has the characteristics
# of a set, but its elements cannot be changed once assined.
# while tuples are immutable lists, frozensets are immutable sets
# initialize A and B
myset1 = frozenset([1, 2, 3, 4, 5, 6, 7, 8, 9])
myset2 = frozenset([1, 2, 3])
print(myset1)
print(myset2)
print(myset1.union(myset2))
print(myset1.intersection(myset2))
print(myset1.difference(myset2))
print(myset1.symmetric_difference(myset2))
#myset1.add(10)




# lecture 9-Python Different Modules

#importing module as well as renaming it.
import math as m

print("The value of pi is", m.pi)

# Usage of from
from math import pi
print("The value of pi is", pi)

#import all names from the standard module math
from math import *
print("The value of pi is", pi)






# lecture 10: Python Directory And File management

import os
print(os.getcwd())   #Returns the present working directory
print(os.getcwdb())  #Returns the present working directory as a byte object

os.chdir('C:/Users/krishna/Desktop') #use to change directory
print(os.getcwd())   #Returns the present working directory
print(os.listdir())  #Returns a list containing the names of the entries in the directory given by path
os.mkdir('newfolder')

#used to make a new directory
os.mkdir('krishna')

#used to rename a directory
os.rename('krishna', 'krishna1')

#removing a file and directory
os.remove('newfile.txt') #use to remove a file
os.rmdir('newfolder') #use to remove a directory
os.rmdir('krishna1')
os.chdir('C:/Users/krishna/Desktop')

7) lecture 11 to 20 

# lec 11 python Dictionary

#Accessing value from Dictionary
from multiprocessing import Value
from traceback import print_tb


new_dict = {1:"Hello", 2:"Hi", 3:"Hey"}
print(new_dict)
print(new_dict[1])
print(new_dict.get(2))

#updating value
new_dict[1] = "Hello World"
print(new_dict)

# Adding value
new_dict[4] = "Hi World"
print(new_dict)

# Creating a new dictionary
squares = {1:1, 2:4, 3:9, 4:16, 5:25}
print(squares)

#remove a particular item
print(squares.pop(3))
print(squares)

#remove an arbitrary item
print(squares.popitem())
print(squares)

# delete a particular item
del squares[1]
print(squares)


# creating a new dictionary using Comprehension
# squares = {X: x*x for x in range(6)}
# print(squares)

#dictionary Membership test
squares = {1:1, 2:4, 3:9, 4:16, 5:25}
print(1 in squares)
print(2 not in squares)
# membership test for key only not value
print(49 in squares)


#iterating through a dictionary
squares = {1:1, 2:4, 3:9, 4:16, 5:25}
for i in squares:
    print(i, squares[i])
    print(i, squares.get(i))

#Using buil-in functions in a dictionary
squares = {1:1, 2:4, 3:9, 4:16, 5:25}
print(len(squares)) #prints the length of the dictionary
print(squares.values())
print(squares.keys())
print(squares.items())
print(sorted(squares)) #prints the dictionary in sorted order




#Lecture 12: Python Strings

#different ways to define a string in python
mystr1 = "Welcome"
print(mystr1)
mystr2 = 'Welcome'
print(mystr2)
mystr3 = """Welcome"""
print(mystr3)
mystr4 = '''Welcome'''
print(mystr4)
mystr5 = "Welcome to the world of python"
print(mystr5)

#triple quotes string can extend multiple lines
mystr3 = """Welcome to the world of python"""
print(mystr3)


#accessing characters in a string
mystr = "Welcome"
print('mystr = ', mystr)
print('mystr[0] = ', mystr[0])
print('mystr[-1] = ', mystr[-1])
print('mystr[1:5] = ', mystr[1:5])
print('mystr[3:] = ', mystr[3:])
print('mystr[:5] = ', mystr[:5])

#strings are immutable
#but different strings can be assigned

mystr = "Welcome"
print(mystr)

mystr = "Welcome to python"
print(mystr)

#concatenation of strings
str1 = "Welcome"
str2 = "to"
str3 = "python"
print(str1 + str2 + str3)

#using +
str1 = "Welcome"
str2 = "to"
str3 = "python"
print(str1 + " " + str2 + " " + str3)

# using *
str1 = "Welcome"
print(str1 * 3)

#iterating through a string
letter_count = 0
for letters in 'Hello world':
    if(letters == '1'):
        letter_count += 1
print(letter_count,'times 1 letter has been found')

#string membership
print ('1' in "hello")
print ('1' not in "hello")
print ('b' in "hello")
print ('b' not in "hello")

#built-in functions in python
mystr = 'cold'

#using emumerate()
my_list_enumerate = list(enumerate(mystr))
print('my_list_enumerate(mystr) ',my_list_enumerate)

#using character count
print ('len(mystr) = ', len(mystr))

#string formating using escape sequence
#print("tell me "what's your name?")

#using triple quotes
print("tell me \"what's your name?\"")

#escaping single quotes
print('tell me \'what\'s your name?\'')

#escaping single quotes
print('tell me \'what\'s your name?\'')

#escaping double quotes
print("tell me \"what's your name?\"")

print("D:\\python\\python39\\python.exe")
print("this line is having a new line \ncharacter")
print("this line is having a tab \tcharacter")  
print("ABC  writen in \x41 character\x42\x43 (HEX) representation")

#format(Method)
#default (implicit) order
default_order = "{}, {} and {}".format('John','Bill','Sean')
print('default_order', default_order)

#order using positional argument
positional_order = "{1}, {0} and {2}".format('John','Bill','Sean')
print('positional_order', positional_order)

#order using keyword argument
keyword_order = "{s}, {b} and {j}".format(j='John',b='Bill',s='Sean')
print('keyword_order', keyword_order)


#formatting Numbers
print("Binary representation of {0} is {0:b}".format(12))

#formatting floats
print(f"Exponent representation:{0:e}".format(1566.345))

# round off
print("One third is {0:.3f}".format(1/3))


#string methods
print("gOOD moRNING tO aLl".lower())
print("gOOD moRNING tO aLl".upper())
print("gOOD moRNING tO aLl".find('tO'))
print("gOOD moRNING tO aLl".find('to'))
print("gOOD moRNING tO aLl".replace('tO','to'))
print("gOOD moRNING tO aLl".replace('all','everybody'))


# LECTURE 13: Python Data Type Conversion

#implicit Type Conversion
num_int = 123
num_float = 1.23

num_new = num_int + num_float
print("Value of num_new ",num_new)
print("Type of num_new ",type(num_new))

print("datatype of num_int ",type(num_int))
print("datatype of num_float ",type(num_float))

#Addition of string(higher) Data type and integer(lower) datatype
num_int = 123
num_str = "456"
print("Type of num_int ",type(num_int))
print("Type of num_str ",type(num_str))
#Error: Implicit conversion will not work heare
#print(num_int+num_str)

# explicit Type Conversion
num_int = 123
num_flo = 1.23

num_new = num_int + num_flo

print("datatype of num_new ",type(num_new))
print("datatype of num_flo:",type(num_flo))

print("Value of num_new: ",num_new)
print("datatype of num_new:",type(num_new))

#Addition of string(higher) Data type and integer(lower) datatype
num_int = 123
num_str = "456"
print("Type of num_int ",type(num_int))
print("Type of num_str ",type(num_str))
print("Value of num_int + num_str: ", num_int + int(num_str))
print("Type of num_int + num_str: ", type(num_int + int(num_str)))

#Explicit type Conversion
num_int = 123
num_str = "456"

print("Data type of num_int: ", type(num_int))
print("Data type of num_str before type Casting: ", type(num_str))
num_str = float(num_str) #Converting string into float
print("Data type of num_str after type Casting: ", type(num_str))
print("Value of num_str after Casting: ", num_str)

num_str = int(num_str) #Converting string into int
print("Data type of num_str after type Casting: ", type(num_str))

num_sum = num_int + num_str
print("Sum of num_int + num_str: ", num_sum)
print("Type of num_sum: ", type(num_sum))


# Lecture 14:Python Numbers

value1 = 100
print(type(value1))
# print(type(value1,int))
# print(type(value1,float))
#print(type(value1,complex))
value2 = 100.24
print(type(value2))
#print(type(value2,int))
#print(type(value2,float))
#print(type(value2,complex))

value3 = 100+200j
print(type(value3))
#print(type(value3,int))
#print(type(value3,float))
#print(type(value3,complex))

print (0b1101)
print (0xab)
print (0o23)

print (10 + 33.4)

#type conversion
print(int(10.5))
print(float(10))
print(complex(10))
print(int(-20.99))


# Python decimal
data1 = 0.1 + 0.2
print(data1)
data1 = 1.20 * 2.50
print(data1)
from decimal import Decimal as D
print(D('0.1') + D('0.2'))
print(D('1.20') * D('2.50'))




# #Python Functions
# from fraction import Fraction as F
# print (F(1,2) + F(1,2))
# print(F(1.5))
# print(F(5))

#Python math Module
import math
print(math.sqrt(16))
print(math.pi)
print(math.cos(10))
print(math.log(10))
print(math.log10(10))
print(math.log2(10))
print(math.ceil(10.1))
print(math.exp(10))
print(math.floor(10.99))
print(math.factorial(5))
print(math.fabs(-10.1))
print(math.sinh(10))
print(math.tanh(10))
print(math.pow(2,3))
print(math.sqrt(16))
print(abs(-12.34))

#Python random Module
import random
print('Random number -> ', random.randrange(5,15))
print('Random number -> ', random.randrange(5,15))
print('Random number -> ', random.randrange(5,15))
print('Random number -> ', random.randrange(5,15))

day = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
print('Random day -> ', random.choice(day))

print('Random day -> ', random.choice(day))
print (day)
random.shuffle(day)
print (day)

#print random element
print(random.random())



#LECTURE 15: Python Namespace and scope

#Name (also called identifier) is simply a name given to objects.

#We can get  the address (in RAM) of some object through the built-in id() function.
# Note:  You may get different value of id

a = 2
#Output: id(2)= 10919424
print('id(2) = ', id(2))

#Output: id(a) =  10919424
print('id(a) = ', id(a))

a = 2
#Output: id(a) = 10919456
print('id(a) = ', id(a))

a = a + 1
# Output: id(a) = 10919424
print('id(a) = ', id(a))

#Output: id(3) = 10919456
print('id(3) = ', id(3))

b = 2
#Output: id(2) = 10919456
print('id(2) = ', id(2))


#Scope
def outer_function():
    global a
    a = 5
    print(a)
    def inner_function():
        a = 10
        print('a =', a)

    inner_function()
    print('a =', a)

a = 10
print('a =', a)
outer_function()
print('a =', a)



# Lecture 16: Python global local nonlocal

#Global and local variables with Defferent name
x = "Global" # Global variable can be accesses from anywhere

def func1():
    global x
    y = "Local"
    x = x * 2
    print('x =', x)
    print('y =', y)

print("Global x = ", x)
func1()
print("Global x = ", x)


#Global and local variables with same name
a = 5

def func2():
    a = 10   #local variables are accessed from the block where it is defined only
    print('a =', a)

print("global a:", a)
func2()
print("global a:", a)

#creating and Using a Non-Local variable

def outer():
    x = "local"

    def inner():
        nonlocal x
        x = "nonlocal" # Nonlocal variable are used in nested function
        print("inner:", x)
    inner()
    print("outer:", x)
outer()


#Lecture 17: Python Global Keywords

def func1():
    x = 20

    def func2():
        global x #Global keyword is used to modify the global variable in a local scope
        x = 30
        print("x = ", x)

    print("Before Calling funct2: ", x)
    print("Calling funct2 now ")
    func2()
    print("After Calling funct2: ", x)
func1()
print("X in main: ", x)


# Lecture 18: Python Iterators

#defining a list
Our_List = [44, 77, 11, 33]

#get an iterator using iter() method
our_iter = iter(Our_List)

##iterate through it using next() method

#prints 44
print(next(our_iter))

#prints 77
print(next(our_iter))

## next(obj) is same as calling abj. __next__() method

#prints 11
print(our_iter.__next__())

#prints 33
print(our_iter.__next__())

#this will raise error, no items leftnext(our_iter)


# creating a custom iterator
class Pow_of_Two:
    '''Class to implement an iterator
    of powers of two'''

    def __init__(self, max = 0):
        self.max = max

    def __iter__(self):
        self.n = 0
        return self

    def __next__(self):
        if(self.n <= self.max):
            result = 2 ** self.n
            self.n += 1
            return result
        else:
            raise StopIteration

print(Pow_of_Two.__doc__)
a = Pow_of_Two(4)
i = iter(a)
print(next(i))
print(next(i))
print(next(i))

# Creating an infinite custom iterator
class Infinite_Iter:
    """Infinite iterator to return all odd numbers"""
   
    def __iter__(self):
        self.n = 1
        return self

    def __next__(self):
        num = self.n
        self.n += 2   # FIX: use self.n, not self.num
        return num

i = Infinite_Iter()
a = iter(i)

print(next(a))  # 1
print(next(a))  # 3
print(next(a))  # 5


#Lecture 19: Python Iterations Using for

#Printing all the elements present in a set
a = [1,2,3,4,5]
for i in a:
    print(i)


#using range in for loop
for i in range(6,11):
    print(i)

#Using range for loop for printing the values present in the
# tuple and using the else command in the for loop
b = (11,12,13,14,15)
for i in b:
    print(i)
else:
    print("printing Completed!")

#lecture 20: Python Innheritance and polymorphism
class myBird:

    def __int__ (self):
        print("myBird class constructor is executing...")

    def whatType(self):
        print("I am a bird")

    def canSwim(self):
        print("I can swim...")

#myPenguin class inheriting the attributes from the myBird class
class myPenguin(myBird):
    def __init__(self):
        # call super() function
        print("myPenguin class constructor is executing...")

    def whoisThis(self):
        print("I am a penguin")

    def canRun(self):
        print("I can run faster...")

#Accessing the child class's attributes(inheritance)

pg1 = myPenguin()
pg1.whatType() #define in myBird class
pg1.canSwim() #define in myBird class
pg1.whoisThis() #define in myPenguin class
pg1.canRun() #define in myPenguin class



#polymorphism
class MyParrot:
    def canfly(self):
        print("Parrot can fly")
    def canswim(self):
        print("Parrot can't swim")

class MyPenguin:
    def canfly(self):
        print("Penguin can't fly")
    def canswim(self):
        print("Penguin can swim")

def flying_test(bird):
    bird.canswim()

# common interface
def flying_bird_test(bird):
    bird.canswim()
    bird.canfly()

#instantiate objects
bird_parrot = MyParrot()
bird_penguin = MyPenguin()

#passing the object
flying_test(bird_parrot)
print()
flying_test(bird_penguin)
flying_bird_test(bird_parrot)
flying_bird_test(bird_penguin)

8) lecture 21 to 30 

# Lecture 21 : Python Multiple Inheritance

#multiple Inheritance
class base1:
    pass
class base2:
    pass
class MultiDerived(base1, base2):
    pass

#Multiple Inheritance
class Base1:
    def  funcBase1(self):
        print("funcBase1() is executing...")

class Base2:
    def funcBase2(self):
        print("funcBase2() is executing...")

class Base3:
    def funcBase3(self):
        print("funcBase3() is executing...")

class MultiDerived(Base1, Base2, Base3):
    def funcMultiDerived(self):
        print("funcMultiDerived() is executing...")

md1 = MultiDerived()
md1.funcBase1()
md1.funcBase2()
md1.funcBase3()
md1.funcMultiDerived()


#Lecture : 22 : Python Function Arguments

def findMax(a, b):
    if a > b:
        return a
    else:
        return b

print ("Max number between 10 and 20 is ",findMax(10, 20))
print ("Max number between 100 and 200 is ",findMax(100, 200))

def hello(name, msg = ", how are you"):
    print("Hello", name, msg)

hello("Krishna",", have a nice day")
hello("Krishna")

def sumAll(*args):
    sum = 0
    for i in args:
        sum += i

    return sum

print("Sum of all the integers is :",sumAll(1, 2, 3, 4, 5))

def defaultArg(a,b,c):
    print("a:",a,"b:",b,"c:",c)

defaultArg(1,2,3)
defaultArg(10,20,30)
defaultArg(1,2,c=3)
defaultArg(a=1,b=2,c=3)

# Lecture : 23 : Python Functions.

def Hello1():
    print("Hello1() function is executing...")
def Hello2():
    print("Hello2() function is executing...")
    return "Hello! i love python programming..."
def Hello3():
    print("Hello3() function is executing...")

Hello1()
Hello2()
Hello3()
print(Hello2())

def myAddition(x,y):
    print("myAddition() function is executing...")
    return (x + y)

def mySubtraction(x,y):
    print("mySubtraction() function is executing...")
    return (x - y)
def myMultiplication(x,y):
    print("myMultiplication() function is executing...")
    return (x * y)
def myDivision(x,y):
    print("myDivision() function is executing...")
    return (x / y)
def myModulo(x,y):
    print("myModulo() function is executing...")
    return (x % y)
def myMenu():
    print("Main Menu...")
    print("1. Addition")
    print("2. Subtraction")
    print("3. Multiplication")
    print("4. Division")
    print("5. Modulo")
    ch = int(input("Enter your choice: "))
    return ch
def myCalculator():
    while True:
        ch = myMenu()
        if ch == 1:
            num1 = int(input("Enter first number: "))
            num2 = int(input("Enter second number: "))
            print("Sum of",num1,"and",num2,"is",myAddition(num1, num2))
        elif ch == 2:
            num1 = int(input("Enter first number: "))
            num2 = int(input("Enter second number: "))
            print("Difference of",num1,"and",num2,"is",mySubtraction(num1, num2))
        elif ch == 3:
            num1 = int(input("Enter first number: "))
            num2 = int(input("Enter second number: "))
            print("Product of",num1,"and",num2,"is",myMultiplication(num1, num2))
        elif ch == 4:
            num1 = int(input("Enter first number: "))
            num2 = int(input("Enter second number: "))
            print("Quotient of",num1,"and",num2,"is",myDivision(num1, num2))
        elif ch == 5:
            num1 = int(input("Enter first number: "))
            num2 = int(input("Enter second number: "))
            print("Remainder of",num1,"and",num2,"is",myModulo(num1, num2))
        else:
            print("Invalid choice...")
        break
    print("Thank you for using my calculator...")
    myCalculator()


#LECTURE 24 : Python break Statement
# import random as r

# rand_num = r.randrange(1, 20)
# print("Number to be guessed...")

# while True:
#     num = int(input("Enter a number: "))

#     if num == rand_num:
#         print("🎉 Congratulations! You guessed the correct number.")
#         break
#     elif num > rand_num:
#         print("⬆️ Your guess is more than the number.")
#     else:
#         print("⬇️ Your guess is less than the number.")


#lecture 25 : Python continue Statement
# program to print only the even numbers from 1 to 19 using continue

for i in range(1,20):
    if i % 2 != 0:
        continue
    print(i)
    i += 1
    print("Loop is executing...")

#LECTRURE 26: Python Errors And Exceptions

try:
    """ the code which can give rise to exception is written inside try block """
    print("Code inside try block")
except:
    """ the code which is executed when exception occurs is written inside except block """
    print("Code inside except block")
finally:
    """ the code which is executed at last whether exception occurs or not is written inside finally block """
    print("Code inside finally block")

#Catching specific exeption
try:
    """ the code which can give rise to exception is written inside try block """
    print("Code inside try block")
    x = 1 / 0
except ZeroDivisionError:
    """ the code which is executed when exception occurs is written inside except block """
    print("Code inside except block")
finally:
    """ the code which is executed at last whether exception occurs or not is written inside finally block """
    print("Code inside finally block")

#exeptions can be raised also

try:
    """ the code which can give rise to exception is written inside try block """
    print("Code inside try block")
    x = 1 / 0
except ZeroDivisionError:
    """ the code which is executed when exception occurs is written inside except block """
    print("Code inside except block")
finally:
    """ the code which is executed at last whether exception occurs or not is written inside finally block """
    print("Code inside finally block")

#LECTURE 27: Python Try, Except And Finally

#Catching specific exeption
try:
    a = 100
    b = 20
    c = a / b
except ZeroDivisionError:
    print("Code inside except block")



#LECTURE 28: Python User Defined Exception
class VoterEligibilityError(Exception):
    """ This is user defined exception """
    def __int__(self):
        super()

try:
    age = 12
    if age < 18:
        raise VoterEligibilityError
except VoterEligibilityError:
    print("Code inside except block")
else:
    print("Code inside else block")
finally:
    print("Code inside finally block")


#Lecture 29: Python OOP Approach

#Creating Class and Object in Python
class myBird:
   
    def __init__(self):
       print("myBird class constructor is executing...")
    def whatType(self):
        print("I am a bird")
    def where(self):
        print("I live in India")

class myParrot:
    #class Attribute
    species = "bird"

    #instance Attribute
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def canSing(self, song):
        return "{} sings {}".format(self.name, song)


#myParrot class inheriting the attributes from the myBird class
class myPenguin(myBird):
    def __init__(self):
        # call super() function
        super().__init__()
        print("myPenguin class constructor is executing...")

    def whoisThis(self):
        print("I am a penguin")
    def canRun(self):
        print("I can run")

#instantiating the myParrot class
mp1 = myParrot("Kesari", 10)
mp2 = myParrot("gunja", 10)

#access the class attribute
print("myParrot class species attribute:",myParrot.species)
print("myParrot class name attribute:",mp1.name)
print("myParrot class age attribute:",mp1.age)
print("myParrot class canSing() method:",mp1.canSing("Happy"))


#data Encapsulation
class personalComputer:
    def __init__(self):
        self.maxComputerPrice = 20000

    def mySell(self):
        print("Selling Price: {}".format(self.maxComputerPrice))
    def setMaxComputerPrice(self, price):
        self.maxComputerPrice = price

pc = personalComputer()
pc.mySell()

#change the price
pc.setMaxComputerPrice(25000)
pc.mySell()

#using setter function
pc.setMaxComputerPrice(30000)
pc.mySell()


#Lecture 30: Python Nested Dictionary Implementation
people = {1: {'Name': 'John', 'Age': '27', 'gender': 'Male'},
          2: {'Name': 'Marie', 'Age': '22', 'gender': 'Female'},
          3: {'Name': 'Mike', 'Age': '32', 'gender': 'Male'},
          4: {'Name': 'Sara', 'Age': '29', 'gender': 'Female'}}
for key, value in people.items():
    print(key, "=>", value)

    for key, value in value.items():
        print(key, "=>", value)

print(people[1]['Name'])
print(people[2]['Age'])
print(people[3]['gender'])

#Adding elements in dictionary
people[5] = {'Name': 'David', 'Age': '31', 'gender': 'Male'}
print(people[5]['Name'])
print(people[5]['Age'])
print(people[5]['gender'])

#added Dictionary to a nested dictionary
people[6] = {'Name': 'David', 'Age': '31', 'gender': 'Male'}
print(people[6]['Name'])
print(people[6]['Age'])
print(people[6]['gender'])

#Deleting elements from a dictionary
del people[1]
print(people)
del people[2]
print(people)
del people[3]
print(people)
del people[4]
print(people)
del people[5]
print(people)
del people[6]
print(people)

#iterating through a nested dictionary
# iterating through a nested dictionary
for p_id, p_info in people.items():
    print("\nPerson ID:", p_id)

    for key in p_info:
        print(key, "=>", p_info[key])

9) LECTURE 31 to 40 

# Lecture 31 : Python Operator Overloading
# Operator Overloading
from os import PRIO_USER
from time import process_time
from tkinter import PROJECTING, W
from typing import Sequence


class myPoint:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def __str__(self):
        return "({0},{1})".format(self.x, self.y)
   
    #Overloading + operator
    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        return myPoint(x, y)

    #Overloading - operator
    def __sub__(self, other):
        x = self.x - other.x
        y = self.y - other.y
        return myPoint(x, y)
   
    #Overloading * operator
    def __mul__(self, other):
        x = self.x * other.x
        y = self.y * other.y
        return myPoint(x, y)
    #Overloading / operator
    def __truediv__(self, other):
        x = self.x / other.x
        y = self.y / other.y
        return myPoint(x, y)
    #Overloading // operator
    def __floordiv__(self, other):
        x = self.x // other.x
        y = self.y // other.y
        return myPoint(x, y)
    #Overloading % operator
    def __mod__(self, other):
        x = self.x % other.x
        y = self.y % other.y
        return myPoint(x, y)
    #Overloading ** operator
    def __pow__(self, other):
        x = self.x ** other.x
        y = self.y ** other.y
        return myPoint(x, y)
    #Overloading + operator
    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        return myPoint(x, y)
   
    #Overloading < operator
    def __lt__(self, other):
        self_mag = (self.x ** 2) + (self.y ** 2)
        other_mag = (other.x ** 2) + (other.y ** 2)
        return self_mag < other_mag

p1 = myPoint(1, 2)
p2 = myPoint(4, 5)
print(p1 < p2)
print(p1 > p2)
# print(p1 <= p2)
# print(p1 == p2)
# print(p1 >= p2)
print(p1 != p2)
print(p1)
print(p2)
print(p1 + p2)
print(p1 - p2)
print(p1.__sub__(p2))
print(p1.__add__(p2))

#lecture 32 : Python Statements and Comments

# Single line comment
# This is a comment
# Multi line comment
"""
This is a comment
written in
more than just one line
"""

# Statement - Assignment statement
a = 1

#Multiple statement
#Explicit line Continuation -'\'
b = 1 + 2 + 3 + 4 + 5 + \
    6 + 7 + 8 + 9 + 10
print(b)
#implicit line continuation within brackets
c = (1 + 2 + 3 +
     4 + 5 + 6 +
     7 + 8 + 9 +
     10)
print(c)

#Multiple statement in one line using - ';'
d = 1; e = 2; f = 3
print(d, e, f)

#code block (body of a function, loop etc) starts with indentation
# and ends with the first unindented statement
for i in range(10):
    print(i)
    if i == 5:
        break
print("End of the program...")

# Lecture 33 :Python Pass Statement

#Pass is just a placeholder for
#functionality to be added later
Sequence = {'p','a','s','s'}
for val in Sequence:
    pass
print("End of the Program...")

#Lecture 34 : Python Generators

# A simple generator function

def my_generator():
    n = 1
    print('This is printed first')
    #Generator function contains yield statements
    yield n

    n += 1
    print('This is printed second')
    yield n

    n += 1
    print('This is printed at last')
    yield n

a = my_generator()
#Iterrating using next
next(a)
next(a)
next(a)
print("Using for loop...")
for item in my_generator():
    print(item)

#Generators with a loop
def reverse_string(my_string):
    length = len(my_string)
    for i in range(length-1, -1, -1):
        yield my_string[i]

for char in reverse_string("hello"):
    print(char)

#Lecture 35 : Python Decorators
#Demonstration
def make_decorated(func):
    def inner_function():
        print("Decorator function")
        func()
    return inner_function
def simple_function():
    print("Simple function")

decor = make_decorated(simple_function)
decor()


#Another example
def my_smart_div(func):
    def inner_function(a, b):
        if b == 0:
            print("B is zero, so we cannot divide")
            return
        return func(a, b)
    return inner_function

@my_smart_div
def go_divide(a, b):  #Generally, we decorate a function and reassign it as,
    return a / b   #go_divide = my_smart_div(divide)
print(go_divide(10, 2))
print(go_divide(10, 0))


#Lecture 36 : Python while loop
#Using while loop
i = 3
while i > 0:
    print(i)
    i -= 1

while i < 10:
    print(i)
    i += 1
else:
    print("End of while loop")

#A program to display a pattern using loops

n = 6

n = int(input("Please enter the number of layers: "))
i = 1
while i <= n:
    j = 1
    # printing dots
    while j <= n - i:
        print(".", end="")
        j += 1
    j = 1
    # printing stars
    while j <= 2*i - 1:
        print("*", end="")
        j += 1
    print()
    i += 1

#  A program to display a pattern using loops

n = int(input("Please enter the number of layers...:"))
m = (n+1)/2
i = 1
while i <= n:
    if (i > m):
        b = n-i
        s = 2*(i-m)+1
    else:
        b = i-1
        s = 2*(m-i)+1
    j = 1
    while j <= b:
          print(".", end="")
          j = j + 1
    j = 1
    while j <= s:
          print("*", end="")
          j = j + 1
    print()
    i += 1


#Lecture 37 : Python use of If,elif,else

#if ... elif ... else
age = int(input("Please enter the age of the person..."))
if age < 5:
    print("Too Young")
elif age == 5:
    print("KinderGarten")
elif age >= 5 and age <= 18:
    print("School")
elif age > 18 and age < 60:
    print("Work")
else:
    print("Retired")

#Nested if
num = int(input("Please enter a number..."))
if num >= 0:
    if num == 0:
        print("Zero")
    else:
        print("Positive number")
else:
    print("Negative number")

#in this program, we input a number
#check if the number is positive or
#negative or zero and display it
# an appropriate message is displayed
#this time we use nested if

num = float(input("Please enter a number...:"))
if num >= 0:
    if num == 0:
        print("Zero")
    else:
        print("Positive number")
else:
    print("Negative number")

#Lecture 38: Python Matrix Implementation

# a is 2-D matrix with integers
a = [['Roy',80,75,85,90,95],
      ['Kia',75,80,75,90,100],
      ['San',70,75,80,75,90]]

#b is a nested list but not a matrix
b = [['Roy',80,75,85,90,95],
      ['Kia',75,80,75,90,100],
      ['San',70,75,80,75,90]]
print(a)
print(b)
print()

# creating a dynamic matrix
n = 3
m = 4
a = [0] * n
print (a)
for i in range(n):
    a[i] = [0] * m
print(a)

# Accessing elements of a matrix
print(a)
print(a[0])
print(a[0][1])
print(a[1][2])

#Negative elements from a matrix
print(a)
print(a[-1])
print(a[-1][-2])
print(a[-2][-3])

#change elements of a matrix
print(a)
b =a[0]
print(b)

b[1]=75
print(a)
print(b)

a[2]=['Sam',80,75,80,75,90]
print(a)

# Lecture 39: Python Regular Expressions

#Regular expressions allow you to locate and change
#strings in very powerful ways
#they work in almost exactly the same way in every
# programming language as well

#Regular Expressions (regex) are used to
#1 . Search for a specific string in a large amount of data
#2. Verify that a string has a proper format(Email, Phone number)
#3. Find a string and replace it with another string
#4. Format data into the proper form for importing for example

# import the Regax module
import re

#-------- Was a Match Found -----------

#Search for ape in the string
if re.search("ape", "The ape was at the apex"):
    print("There is an ape")

import re
#---------- GET all Matches ------

#findall() returns a list of matches
#. is used to match any single character or space
print(re.findall("ape.", "The ape was at the apex"))
allApes = re.findall("ape.", "The ape was at the apex")
for i in allApes:
    print(i)

#finditer returns an iterator of matching objects
# you can use to get the location

theStr = "The ape was at the apex"

for i in re.finditer("ape.", theStr):
    #Span returns a tuple
    locTuple = i.span()

    print(locTuple)

    #Slice the match out using the tuple values
    print(theStr[locTuple[0]:locTuple[1]])

import re
#-------- Match 1 of Several letters--------
#Square brackets will match any one of the characters between
#The brackets not included upper and lowercase varieties
#unless they are listed

animalStr = "Cat rat mat fat pat"

allAnimals = re.findall("[crmfp]at", animalStr)
for i in allAnimals:
    print(i)
print()

# Use ^ to denote any character but watever characters are
# betweens the brackets
animalStr = "Cat rat mat fat pat"
someAnimals = re.findall("[^crmfp]at", animalStr)
for i in someAnimals:
    print(i)

print()


import re
#------------ Solving BlackSlash Problems-------

#Regex use the backslash to escape special characters
# and Python does the same inside strings which causes
# issues

# Lets try to get "//stuff" out of a string

randStr = "Here is \\stuff"

#This wont find it
print(re.findall("\\stuff", randStr))

#This does, but we have to put in 4 slashes which is
#messy
print(re.findall("\\\\stuff", randStr))
print("Find \\stuff :", re.search("\\\\stuff", randStr))

#You can get around this by using raw strings
#dont blackSlashes as special

import re
#------------- Matching any single Number-------
#\d can be used instead of 9 [0 9]
#\D is the same as [^0-9]

randStr = "123abc#456"
print(re.findall("\d", randStr))
print(re.findall("\D", randStr))

import re
#------------- Matching Multiple Numbers--------
#you can match multiple digits by following the \d with {numofValues}

#Match 5 numbers only
if re.search("\d{5}", "12345"):
    print("Found a match!")
else:
    print("Not matched!")

#You can also match within a range
#Match values that are between 5 and 7 digits
numStr = "123 12345 1234567"

print(" Matches :", len(re.findall("\d{5,7}", numStr)))

import re

#---------------Matching WhiteSpace ----------
# \s is the Same as [\f\n\r\t\v]
# \S is the Same as [^\f\n\r\t\v]

#Check for valid first and last name with a space
if re.search("\S \S", "123 12345 1234567"):
    print("Found a match!")
else:
    print("Not matched!")




#Lecture 40 : Python List Comprehension

#Iterating a string through a for loop and adding the letters a list
h_letters = []

for letter in "human":
    h_letters.append(letter)
print(h_letters)

#Using list comprehension
h_letters = [letter for letter in "human"]
print(h_letters)

#Using list comprehension with a condition
even_letters = [letter for letter in "human" if letter != "a"]
print(even_letters)

#list Comprehension vs Lambda Functions
h_letters = list(map(lambda x: x, "human"))
print(h_letters)

#if with list comprehension
number_list = [ X for x in range(10) if x%2 == 0]
print(number_list)

#Nested if with list comprehension
num_list = [ x for x in range(100) if x%2 == 0 if x%5 == 0]
print(num_list)

#if ..Else with list comprehension
obj = ["Even" if i%2==0 else "Odd" for i in range(10)]
print(obj)

#transposing a matrix using a list comprehension
matrix = [[1,2,3],[4,5,6],[7,8,9]]
transpose = [[row[i] for row in matrix] for i in range(3)]
print(transpose)


10) Lecture 41 to 50 The END...................

# Lecture 31 : Python Operator Overloading
# Operator Overloading
from os import PRIO_USER
from time import process_time
from tkinter import PROJECTING, W
from typing import Sequence


class myPoint:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def __str__(self):
        return "({0},{1})".format(self.x, self.y)
   
    #Overloading + operator
    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        return myPoint(x, y)

    #Overloading - operator
    def __sub__(self, other):
        x = self.x - other.x
        y = self.y - other.y
        return myPoint(x, y)
   
    #Overloading * operator
    def __mul__(self, other):
        x = self.x * other.x
        y = self.y * other.y
        return myPoint(x, y)
    #Overloading / operator
    def __truediv__(self, other):
        x = self.x / other.x
        y = self.y / other.y
        return myPoint(x, y)
    #Overloading // operator
    def __floordiv__(self, other):
        x = self.x // other.x
        y = self.y // other.y
        return myPoint(x, y)
    #Overloading % operator
    def __mod__(self, other):
        x = self.x % other.x
        y = self.y % other.y
        return myPoint(x, y)
    #Overloading ** operator
    def __pow__(self, other):
        x = self.x ** other.x
        y = self.y ** other.y
        return myPoint(x, y)
    #Overloading + operator
    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        return myPoint(x, y)
   
    #Overloading < operator
    def __lt__(self, other):
        self_mag = (self.x ** 2) + (self.y ** 2)
        other_mag = (other.x ** 2) + (other.y ** 2)
        return self_mag < other_mag

p1 = myPoint(1, 2)
p2 = myPoint(4, 5)
print(p1 < p2)
print(p1 > p2)
# print(p1 <= p2)
# print(p1 == p2)
# print(p1 >= p2)
print(p1 != p2)
print(p1)
print(p2)
print(p1 + p2)
print(p1 - p2)
print(p1.__sub__(p2))
print(p1.__add__(p2))

#lecture 32 : Python Statements and Comments

# Single line comment
# This is a comment
# Multi line comment
"""
This is a comment
written in
more than just one line
"""

# Statement - Assignment statement
a = 1

#Multiple statement
#Explicit line Continuation -'\'
b = 1 + 2 + 3 + 4 + 5 + \
    6 + 7 + 8 + 9 + 10
print(b)
#implicit line continuation within brackets
c = (1 + 2 + 3 +
     4 + 5 + 6 +
     7 + 8 + 9 +
     10)
print(c)

#Multiple statement in one line using - ';'
d = 1; e = 2; f = 3
print(d, e, f)

#code block (body of a function, loop etc) starts with indentation
# and ends with the first unindented statement
for i in range(10):
    print(i)
    if i == 5:
        break
print("End of the program...")

# Lecture 33 :Python Pass Statement

#Pass is just a placeholder for
#functionality to be added later
Sequence = {'p','a','s','s'}
for val in Sequence:
    pass
print("End of the Program...")

#Lecture 34 : Python Generators

# A simple generator function

def my_generator():
    n = 1
    print('This is printed first')
    #Generator function contains yield statements
    yield n

    n += 1
    print('This is printed second')
    yield n

    n += 1
    print('This is printed at last')
    yield n

a = my_generator()
#Iterrating using next
next(a)
next(a)
next(a)
print("Using for loop...")
for item in my_generator():
    print(item)

#Generators with a loop
def reverse_string(my_string):
    length = len(my_string)
    for i in range(length-1, -1, -1):
        yield my_string[i]

for char in reverse_string("hello"):
    print(char)

#Lecture 35 : Python Decorators
#Demonstration
def make_decorated(func):
    def inner_function():
        print("Decorator function")
        func()
    return inner_function
def simple_function():
    print("Simple function")

decor = make_decorated(simple_function)
decor()


#Another example
def my_smart_div(func):
    def inner_function(a, b):
        if b == 0:
            print("B is zero, so we cannot divide")
            return
        return func(a, b)
    return inner_function

@my_smart_div
def go_divide(a, b):  #Generally, we decorate a function and reassign it as,
    return a / b   #go_divide = my_smart_div(divide)
print(go_divide(10, 2))
print(go_divide(10, 0))


#Lecture 36 : Python while loop
#Using while loop
i = 3
while i > 0:
    print(i)
    i -= 1

while i < 10:
    print(i)
    i += 1
else:
    print("End of while loop")

#A program to display a pattern using loops

n = 6

n = int(input("Please enter the number of layers: "))
i = 1
while i <= n:
    j = 1
    # printing dots
    while j <= n - i:
        print(".", end="")
        j += 1
    j = 1
    # printing stars
    while j <= 2*i - 1:
        print("*", end="")
        j += 1
    print()
    i += 1

#  A program to display a pattern using loops

n = int(input("Please enter the number of layers...:"))
m = (n+1)/2
i = 1
while i <= n:
    if (i > m):
        b = n-i
        s = 2*(i-m)+1
    else:
        b = i-1
        s = 2*(m-i)+1
    j = 1
    while j <= b:
          print(".", end="")
          j = j + 1
    j = 1
    while j <= s:
          print("*", end="")
          j = j + 1
    print()
    i += 1


#Lecture 37 : Python use of If,elif,else

#if ... elif ... else
age = int(input("Please enter the age of the person..."))
if age < 5:
    print("Too Young")
elif age == 5:
    print("KinderGarten")
elif age >= 5 and age <= 18:
    print("School")
elif age > 18 and age < 60:
    print("Work")
else:
    print("Retired")

#Nested if
num = int(input("Please enter a number..."))
if num >= 0:
    if num == 0:
        print("Zero")
    else:
        print("Positive number")
else:
    print("Negative number")

#in this program, we input a number
#check if the number is positive or
#negative or zero and display it
# an appropriate message is displayed
#this time we use nested if

num = float(input("Please enter a number...:"))
if num >= 0:
    if num == 0:
        print("Zero")
    else:
        print("Positive number")
else:
    print("Negative number")

#Lecture 38: Python Matrix Implementation

# a is 2-D matrix with integers
a = [['Roy',80,75,85,90,95],
      ['Kia',75,80,75,90,100],
      ['San',70,75,80,75,90]]

#b is a nested list but not a matrix
b = [['Roy',80,75,85,90,95],
      ['Kia',75,80,75,90,100],
      ['San',70,75,80,75,90]]
print(a)
print(b)
print()

# creating a dynamic matrix
n = 3
m = 4
a = [0] * n
print (a)
for i in range(n):
    a[i] = [0] * m
print(a)

# Accessing elements of a matrix
print(a)
print(a[0])
print(a[0][1])
print(a[1][2])

#Negative elements from a matrix
print(a)
print(a[-1])
print(a[-1][-2])
print(a[-2][-3])

#change elements of a matrix
print(a)
b =a[0]
print(b)

b[1]=75
print(a)
print(b)

a[2]=['Sam',80,75,80,75,90]
print(a)

# Lecture 39: Python Regular Expressions

#Regular expressions allow you to locate and change
#strings in very powerful ways
#they work in almost exactly the same way in every
# programming language as well

#Regular Expressions (regex) are used to
#1 . Search for a specific string in a large amount of data
#2. Verify that a string has a proper format(Email, Phone number)
#3. Find a string and replace it with another string
#4. Format data into the proper form for importing for example

# import the Regax module
import re

#-------- Was a Match Found -----------

#Search for ape in the string
if re.search("ape", "The ape was at the apex"):
    print("There is an ape")

import re
#---------- GET all Matches ------

#findall() returns a list of matches
#. is used to match any single character or space
print(re.findall("ape.", "The ape was at the apex"))
allApes = re.findall("ape.", "The ape was at the apex")
for i in allApes:
    print(i)

#finditer returns an iterator of matching objects
# you can use to get the location

theStr = "The ape was at the apex"

for i in re.finditer("ape.", theStr):
    #Span returns a tuple
    locTuple = i.span()

    print(locTuple)

    #Slice the match out using the tuple values
    print(theStr[locTuple[0]:locTuple[1]])

import re
#-------- Match 1 of Several letters--------
#Square brackets will match any one of the characters between
#The brackets not included upper and lowercase varieties
#unless they are listed

animalStr = "Cat rat mat fat pat"

allAnimals = re.findall("[crmfp]at", animalStr)
for i in allAnimals:
    print(i)
print()

# Use ^ to denote any character but watever characters are
# betweens the brackets
animalStr = "Cat rat mat fat pat"
someAnimals = re.findall("[^crmfp]at", animalStr)
for i in someAnimals:
    print(i)

print()


import re
#------------ Solving BlackSlash Problems-------

#Regex use the backslash to escape special characters
# and Python does the same inside strings which causes
# issues

# Lets try to get "//stuff" out of a string

randStr = "Here is \\stuff"

#This wont find it
print(re.findall("\\stuff", randStr))

#This does, but we have to put in 4 slashes which is
#messy
print(re.findall("\\\\stuff", randStr))
print("Find \\stuff :", re.search("\\\\stuff", randStr))

#You can get around this by using raw strings
#dont blackSlashes as special

import re
#------------- Matching any single Number-------
#\d can be used instead of 9 [0 9]
#\D is the same as [^0-9]

randStr = "123abc#456"
print(re.findall("\d", randStr))
print(re.findall("\D", randStr))

import re
#------------- Matching Multiple Numbers--------
#you can match multiple digits by following the \d with {numofValues}

#Match 5 numbers only
if re.search("\d{5}", "12345"):
    print("Found a match!")
else:
    print("Not matched!")

#You can also match within a range
#Match values that are between 5 and 7 digits
numStr = "123 12345 1234567"

print(" Matches :", len(re.findall("\d{5,7}", numStr)))

import re

#---------------Matching WhiteSpace ----------
# \s is the Same as [\f\n\r\t\v]
# \S is the Same as [^\f\n\r\t\v]

#Check for valid first and last name with a space
if re.search("\S \S", "123 12345 1234567"):
    print("Found a match!")
else:
    print("Not matched!")




#Lecture 40 : Python List Comprehension

#Iterating a string through a for loop and adding the letters a list
h_letters = []

for letter in "human":
    h_letters.append(letter)
print(h_letters)

#Using list comprehension
h_letters = [letter for letter in "human"]
print(h_letters)

#Using list comprehension with a condition
even_letters = [letter for letter in "human" if letter != "a"]
print(even_letters)

#list Comprehension vs Lambda Functions
h_letters = list(map(lambda x: x, "human"))
print(h_letters)

#if with list comprehension
number_list = [ X for x in range(10) if x%2 == 0]
print(number_list)

#Nested if with list comprehension
num_list = [ x for x in range(100) if x%2 == 0 if x%5 == 0]
print(num_list)

#if ..Else with list comprehension
obj = ["Even" if i%2==0 else "Odd" for i in range(10)]
print(obj)

#transposing a matrix using a list comprehension
matrix = [[1,2,3],[4,5,6],[7,8,9]]
transpose = [[row[i] for row in matrix] for i in range(3)]
print(transpose)

#Lecture 41: Python Recursion.

def fact(n):
    if n <=1:
        return 1
    return n * fact(n-1)

print("Factorial of 5 is",fact(5))

#Lecture 42: Python Input, Output And Import

#Print function and its usage
print("This sentence is output to the screen")
#Output: This sentence is output to the screen

a = 5

# print('The value of a is' + str(a))
print('The value of a is',a)
#Output: The value of a is 5

print(1,2,3,4)
#Output: 1 2 3 4

print(1,2,3,4,sep='*')
#Output: 1*2*3*4*

print(1,2,3,4,sep='*',end='&')
#Output: 1*2*3*4&

print('I Love {0} and {1}'.format('Python','Java'))
print('I Love {1} and {0}'.format('Python','Java'))  
#Output: I Love Python and Java

# input
x = input("Enter a value of number: ")
print(x)

#importing module
import math #mainly done at the top of the program
print(math.pow(int(x),2))

#Lecture 43: Python Shallow And Deep Copy

list1 = [[1,2,3],[4,5,6],[7,8,9]]
list2 = list1
print("list1 -> ",list1)
print("List2 -> ",list2)
print("id of list1 -> ",id(list1))
print("id of list2 -> ",id(list2))

list1.append([10,11,12])
print("list1 -> ",list1)
print("List2 -> ",list2)

#Creating a copy using shallow Copy
import copy

old_list = [[1,2,3],[4,5,6],[7,8,9]]
new_list = copy.copy(old_list)
print("old_list -> ",old_list)
print("new_list -> ",new_list)

#Adding elements to the old_list using shallow copy
old_list.append([10,11,12])
print("old_list -> ",old_list)
print("new_list -> ",new_list)

#Adding new nested object using shallow copy
old_list[1][2] = 'AA'
print("old_list -> ",old_list)
print("new_list -> ",new_list)
old_list[3][1] = 'BB'
print("old_list -> ",old_list)
print("new_list -> ",new_list)

#Copying a list using deepcopy()
import copy
old_list = [[1,2,3],[4,5,6],[7,8,9]]
new_list = copy.deepcopy(old_list)

print("old_list -> ",old_list)
print("new_list -> ",new_list)

#Adding a new nested object in the list using Deep Copy
old_list[1][0] = 'BB'
print("old_list -> ",old_list)
print("new_list -> ",new_list)




#Lecture 44: Python Lamda Function

a = lambda x:x*2
          #in Python, anonymous function is a function that is defined without a name.
          #it is defined by lambda

print("Double of 10 is",a(10))

#Making a new list by taking only the even numbers from the list

mylist = [1,2,3,4,5,6,7,8,9,10]
newlist = list(filter(lambda x: (x%2 == 0), mylist))
          # filter function is called with all the items in the list and a new list
          # is returned which contains items for which the function returns true

#Output : [2, 4, 6, 8, 10]
print(newlist)

#program to double each item in a list using map()
mylist = [1,2,3,4,5,6,7,8,9,10]
newlist = list(map(lambda x: x*2, mylist))

#Output : [2, 4, 6, 8, 10]
print(newlist)

#Lecture: 45 Python Assert

#Assertion without error message
def avg(marks):
    assert len(marks) != 0,"List is empty."
    return sum(marks)/len(marks)

mark1 = [11,22,33]
print("Average of mark1:",avg(mark1))
#This will raise an error because the list is empty
mark1 = []
print("Average of mark1:",avg(mark1))

#using assert with error message
def avg(marks):
    assert len(marks) != 0,"List is empty."
    return sum(marks)/len(marks)

mark2 = [11,22,33,44,55]
print("Average of mark2:",avg(mark2))
mark1 = []
print("Average of mark1:",avg(mark1))

#lecture 46: Python File I/O
file = open("test.txt","w")
file.write("Hello World")
file.close()

file = open("test.txt","r")
print(file.read())
file.close()

file = open("test.txt","a")
file.write("Hello World Again")
file.close()

file = open("test.txt","r")
print(file.read())
file.close()

file = open("test.txt","w")

file.write("Hello World Again")

file.close()

file = open("test.txt","r")

print(file.read())

file.close()

#Lecture 46: Python @Property
#Demostrating the use of @property
class Temp_Celsius:
    def __init__(self, temperature = 0):
        print("Assigning Temperature value")
        self._temperature = temperature

    def convert_to_fahrenheit(self):
        return (self._temperature * 1.8) + 32

    def get_temperature(self):
        print("Getting value")
        return self._temperature

    def set_temperature(self, value):
        if value < -273:
            raise ValueError("Temperature below -273 is not possible")
        print("Setting value")
        self._temperature = value
#Property() is a built-in function, creates and returns object
# property(fget=None, fset=None, fdel=None, doc=None)
#property object has three methods, getter(), setter(), and deleter()
#tempreture = property(get_temperature,set_temperature)
# make empty property
temperature = property()
#assign fget
temperature = temperature.getter(get_temperature)
#assign fset
temperature = temperature.setter(set_temperature)

c = Temp_Celsius(37)
print(c.temperature)
print(c.convert_to_fahrenheit())
c.temperature = 100
print(c.convert_to_fahrenheit())
c.temperature = -300
print(c.convert_to_fahrenheit())
print(c.temperature)
print(c.__dict__["_temperature"])
print(c.__dict__["temp"])

#Lecture 47: Python Decorators
def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper
@my_decorator
def say_hello():
    print("Hello!")
say_hello()

#Lecture 48: Python Decorators with Arguments

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Before function execution")
        func(*args, **kwargs)
        print("After function execution")
    return wrapper

@my_decorator
def add(a, b):
    print("Sum:", a + b)

add(5, 3)

#Lecture 49: Generators in Python
#Generators return values one by one using yield instead of return.

def count_up(n):
    i = 1
    while i <= n:
        yield i
        i += 1

for num in count_up(5):
    print(num)

#Lecture 50: Context Managers (with statement)
#Context managers handle resource management automatically.

#Without context manager (problem):
file = open("data.txt", "w")
file.write("Hello Python")
file.close()
#With context manager (best practice):
with open("data.txt", "w") as file:
    file.write("Hello Python")
#----------------------EXIT-----------------------#

--------------------------THE END--------------------------

11)Coming soon 

Post a Comment

0 Comments