Let’s Conquer Python
Python is a dynamically typed, general-purpose programming language that supports an object-oriented programming approach as well as a functional programming approach.
🚎Data Types in Python
🛴Numeric data: int, float, complex
🛴Boolean data:True, False
🛴Sequenced data: list, tuple
🛴Mapped Data:dict
🛴Text data: str
Python does not have a char data type. It can’t differentiate between single and double quotes.
✅Everything is an object in Python.
Typecasting → data type change
Taking Input in Python
a = input() →Whatever it will take,will be taken in the form of string.
Strings
“Hello, \”I am learning” → double quotes inside string
‘Hello, “I am learning’ →This can also be used
Multiple line strings →Triple quotes use
apple = '''Hey
I am a new
I am good'''
String Slicing
names ="Deeksha"
names[startIndex, endIndex]
len(names)
#endIndex include nhi hota
#Negative Slicing
names[0, -3]-->equivalent to names[0, len(names)-3]
String Methods in Python
Strings are immutable in Python. Always a new copy of this will be made whatever operation you will try on it.
a = "Deeksha"
a.upper()
a.lower()
a.rstrip("!") --> All the exclamation marks at the end will be removed
a.replace("Deeksha", "Good")-->Deeksha will be replaced with good at all the places
a.split(" ")-->String will be converted to list.All the words will be separated on the basis of space.
a.capitalize()-->First letter will be capitalized and rest will be converted to smallcase.
a.count('a')
a.find("ee")-->Index of first occurence will be retrieved
If-else
if(condition):
elif(condition):
else:
Matchcase Statements
x = int(input("Enter the value:"))
match x:
case 0:
print("Zero")
case 1:
print("one")
case _:
print("default")
#No need to use break here
we can write default case like this also
case _ if x!=90:
print("ninty")
case _ if x!= 80:
print("eighty")
For loop
for a in apple:
print(a)
for n in range(1, 50):
print(n)
for i in range(1,50, 3)
print(i)
Python Functions
def functionName(a,b):
print("yay!)
def isLesser(a, b):
pass --> I ma trying to say that I will write the definition of this function later.
Function Arguments
#If I want to pass multiple number of arguments
def average(*numbers): -->numbers will be taken as tuple
sum = 0
for i in numbers:
sum = sum+i
print("Average is", sum/len(numbers))
average(5,6)
average(1,5,6,7)
average(1,5,6,7,7,8)
def name(**along): --> dictionary argument is taken using this **
print(type(along))
print("Hello", along["fname"], along["manme"]
name(mname="hi", lname="why", fname="shy")
List in Python
#list is mutable
marks = [3,5,6,"hdh", True]
print(marks[1])
print(marks[-3])-->equivalent to marks[len(marks)-3]
if 6 in marks:
print("Yes")
print(marks[1:4:2) --> 2 is the jump index
lst = [i*i for i in range(10 if i%2 == 0)]
List methods in python
l = [1,2,23,4]
l.append(7) --> 7 will get added into the last of l
l.sort() --> sorts the list in ascending
l.sort(reverse=True) -->sorts the list in descending
l.index(23) --> first occurence of 23 will be given
l.count(4) --> count the occurences of the element 4
#Thing to note
m = l
m[0] = 56 --> original l list will also chnage because m is just a refernce of l
m = l.copy()
m[0] = 56 --> original l will not change
l.insert(1, 22) --> 22 will be inserted at 1 index
m = [234, 56, 78]
l.extend(m) -->open m and put it at the end of l
k = [667, 678]
k = l+m -> list l and m will be merged
Tuples in Python
Tuples are immutable.
tup = (1, 26, 78, 908, "green")
print(type(tup), tup)
tup = (1,) --> For 1 element tuple , has to be applied otherwise python will convert its type to int instead of tuple
tup[0]= 10 --> not allowed
print(tup[1])
print(tup[-4])
if 78 in tup
print("yes")
#slicing in tuple
tup2 = tup[1:4] --> tup2 will be newly created tuple
Operations on Tuples in Python
#You can do changes in tuples like this
countries = ["ru", "ty", "yu"]
temp = list(countries)
temp.append("po")
temp.pop(2)
temp[1] = "lk"
countries = tuple(temp)
#We can concat two tuples
newtup = tup1+tup2
res = countries.count("ty")
res1 = countries.index("ru")
f-strings in python
#Before fstrings string formatting was used to be done in this way
letter = "My name is {} and I am from {}"
country = "India"
name = "Deeksha"
print(letter.format(name, country))
OR
letter = "My name is {1} and I am from {0}"
country = "India"
name = "Deeksha"
print(letter.format(country, name))
#Using fstring
print(f"Hey my name is {name} and I am from {country}") --> now we can put variables in the string since it's a fstring
print(f"{2*30}")
print(f"Hey my name is {{name}} and I am from {{country}}") --> now it will be printed as it is, will not be replaced with variables
Docstrings in python
Docstrings are the string literals that appear right after the definition of a function, method, class or module.
def square(n):
'''This line will be printed and tell about function'''
print(n**2)
square(5)
print(square.__doc__) --> This will print that line in triple quotes
Zen of Python → Python →import this
Sets in Python
Set do not stores duplicate values. It is an unordered set.
s = {2,4,2,6}
s = set() →to create an empty set
Set Methods
s1 = {1,2,3}
s2 = {4,5,6}
s3 = s1.union(s2)
s1.update(s2) --> s1 will be updated with elements of s2
s4 = s1.intersection(s2)
s1.intersection_update(s2)
#symmetric difference-->AUB-AintersectionB-->non common values
s5 = s1.symmetric_difference(s2)
Dictionaries in Python
Ordered collection of data items
dic = {
"Deeksha":"Human"
}
print(dic['Deeksha'])-->Will throw an error if key will not be there
print(dic.get('Deeksha'))-->none will be returned incase key doesnot exist
print(dic.keys()) -->all keys will be retrieved
print(dic.values()) -->all values will be retrieved
print(dic.items()) --> prints all key value pairs
for key,value in dic.items():
print(f"{key} is {value}")
Dictionary Methods
ep1 = {1:2, 2:10, 3:4, 4:5}
ep2 = {33:46}
ep1.update(ep2)
ep1.clear-->all items will be deleted
ep3 = {}-->empty dictionary
ep1.pop(4)-->key value pair with key as 4 will be removed
ep2.popitem()-->last key value pair will be removed
del ep1 --> whole dictionary will be deleted
for loop / while loop with else statement
for i in range(5):
print(i)
if i == 4
break
else:
print("Hey!")-->This will run at athe end only when whole for loop will get over.On break this else part will not run because in that case this whole for loop was not able to execute
Exception Handling in Python
Process of responding to unexpected events.
a = "enter an input"
try:
for(i in range(1, 10):
print(f"{int(a)}*{i}")
except Exception as e:
print(e)
print("End of progrm") --> Now due to try catch this program will not crash and this line will be executed always
#can handle a specific error also
try:
//some code
except ValueError:
print("yo")
except IndexError:
print("ayy")
Finally keyword in Python
def func:
try:
l = [1,2,3]
return 1
except:
return 0
finally:
print("I am always executed")
#Profit of finally is that although return statement executed in the functions even then code under finally will have to run for sure.
#Finally code will run whether you go in try block or except block.
Raising custom errors in Python
a = int(input("Enter any value between 2 and 10"))
if(a<5 or a >9):
raise ValueError("Value should be between 2 and 10")
If else in one line
print("a") if a < b else print("=") if a==b else print("b")
Enumerate function in Python
Built-in function in python that allows us to loop over a sequence and get the index and value of each element.
marks = [12, 30, 98, 100]
for index, mark in enumerate(marks):
print(mark)
if(index==3)
break
Importing in Python
import math
result = math.sqrt(9)
from math import sqrt
result = sqrt(9)
from math import *
result = sqrt(9)
#AS Keyword
import math as m
result = m.sqrt(9)
from math import sqrt as s
res = s(9)
import math
print(dir(math))-->displays all the functions and variables insisde the module
if __name__ ==”__main__”
#In python only by import also functions of file get executed-->Be cautios!
harry.py
def welcome():
print("Hey you are welcome")
print(__name__)
if __name__ == "__main__"-->Run this only when this file gets executed
welcome()
main.py
*******
import harry
harry.welcome()
os Module in Python
import os
if(not os.path.exists("data")):
os.mkdir("data")-->This will create a folder named data
for i in range(0,100):
os.mkdir(f"data/Day{i+1}")-->This will create folders inside data folder
os.rename("data/Day1", "data/Day2") -->renaming the folder
folders = os.listdir("data") -->show all files and folders inside data directory
Global Variable
x = 10
def myFunc:
global x --> Now global x will change frm this function
x = 4
File Handling in Python
f = open('myfile.txt', 'r')
print(f)
text = f.read()
print(text)
f.close()
#Modes in file
r-->read --> default mode
w-->write -->file will be created in case it will not be there
a-->append -->put content at the end of the file
x-->file will be created
rt-->open file in the form of text file
rb-->open file in the form of binary
f = open('myfile.txt', 'w')
f.write('Hello world!)
f.close()
#file will get automatically closed on using with statement
with open('myfile.txt', 'a') as f:
f.write('Hey', I am inside this file)
#readline method reads data line by line until line gets exhausted in the file
#readline reads data line by line
f = open('myfile.txt', 'r')
while True:
line = f.readline()
if not line:
break
print(line)
#writelines
f = open('myfile.txt', 'w')
lines = ['line1\n', 'line2\n']
f.writelines(lines)
f.close()
#seek function
with open("file.txt", 'r') as f:
print(type(f))
f.seek(10) --> cursor will be taken to the 10th byte in the file
#tell function
print(f.tell()) --> tells the current postion of cursor in the file
data = f.read(5) --> 5 characters will be read after the 10th byte
print(data)
Lambda Functions in Python
def double(x):
return x*2
#We can write this above function in one line like this
double = lambda x: x*2
print(double(5))
#You can give as many as arguments you want
avg = lambda x,y: (x+y)/2
print(avg(3,5))
lambda functions are useful when we want to pass function as an argument to a function.
Map, Filter and Reduce in Python
l = [1,2,3,5,9]
def cube(x):
return x*x*x
#map function
newl = list(map(cube, l)) --> In map function firstly pass a function and then pass the list for whose each element you want to run this function
#map by default return map object so convert it into list
#filter function
def filterFunc(a):
return a > 4
newll = list(filter(filterFunc, l))
OR
newll = list(filter(lambda a: a>4 ,l))
#reduce function
from functools import reduce
sum = reduce(lambda sum x,y: x+y ,l)--> 1+2 =3 then 3+3 = 6 then 6+5 = 11 then 11+9 = 20-->final output
Higher order functions are those functions which take functions as arguments. Map, reduce and filter are higher order functions.
is v/s ==
a = [1,2,34]
b = [1,2,34]
print(a is b) --> exact location of object in memory is compared
print(a == b) --> only value is compared
Output:
False
True
#constant, tuple, string, None(immutables) k case mein memory mein ek hi location de jati hai
a = 3
b = 3
print(a is b)
print (a == b)
print ( a is None)
Output:
True
True
True
Classes and Objects in Python
class Person:
name="Deeksha"
def info(self): --> self is a reference to the current object of the class
print(self.name)
Constructors in Python
class Person:
#Parametrized Constructor
def __init__(self,n,o): -->This is a constructor.__init__ is used to create constructor
self.name = n
self.occ = o
a = Person("Deeksha", "Developer")
#Default Constructor
def __init__(self):
print("hey")
Decorators in Python
Decorators are used to modify a function.
def greet(fx):
def mfx():
print("Hello")
fx()
print("Bye")
return mfx
@greet
def hello():
print("Hey")
hello()
OR
greet(hello)()
#When we have to pass arguments
def greet(fx):
def mfx(*args, **kwargs): --> *args takes all the arguments as tuple and **kwargs takes all the arguments as dictionary
print("Hello")
fx(*args, **kwargs)
print("Bye")
return mfx
@greet
def sum(a,b):
print(a+b)
sum(2,5)
OR
def sum(a,b):
print(a+b)
greet(sum(2,3)()
Getters and Setters in Python
class MyClass:
def __init__(self, value)
self.value = value
#getter-->method to access the value of an object-->used for encapsulation
@property
def tenValue(self):
return 10.self.value
#setter
@tenValue.setter-->method to set the value
def tenValue(self, newValue):
self.value = newValue
obj = MyClass(10)
obj.tenValue = 67
print(obj.tenValue)
📌OOPS In Python
class demo:
#Constructor
def __init__(self):
#class variable
self.name = "demoName"
#class functions
def demoFunc(self):
print("I am a function")
🎄self has to be passed in evry class function and self refers to the current instance of the class.
😇Decorators in Python
A decorator is a function that takes another function as an argument and returns the modified function which modifies the behavior of the original function.
def greet(fx):
def modifiedFx():
print("What's up!")
fx()
print("Bye!")
return modifiedFx
def hello():
print("Hello guys!")
👀One way to decorate hello function is:
greet(hello)()
OR
🙄we can write hello function like this
@greet
def hello():
print("Hello guys!")
hello()
These two are exactly same.
Now suppose the function we are trying to decorate needs some arguments like:
def greet(fx):
def modifiedFx(*args, **kwargs):
print("What's up!")
fx(*args, **kwargs)
print("Bye!")
return modifiedFx
@greet
def add(a, b):
return a+b
add(1,2)
OR
greet(add)(1,2) -->In this case @greet need not to be written before add function.
🤡Getters in Python
Getters are methods that are used to access the value of an object property. They are defined with @property decorator.
class demo:
def __init__():
self.d = 10
@property
def getValue(self):
return self.d*10
demoObj = demo()
print(demoObj.getValue)
🤡Setters in Python
Setters are used to set the value of object parameters. Remember Getters do not take arguments but setters take. Setters need to be decorated by the decorator @methodName.setter
class demo:
def __init__(self):
self.d = 10
@setValue.setter
def setValue(self, newValue):
self.value = newValue
demoObj = demo()
demoObj.setValue(100)
😏Inheritance In Python
class Employee:
def __init__(self, name):
self.name = name
#Let's inherit this class
class Programme(Employee):
def sayHello():
print("Hello")
proObj = Programmer("DemoName")
proObj.sayHello()
#Now Programmer class will be having all the properties of the Employee class.
😎Access Modifiers/Specifiers in Python
They are used to limit the access of class variables and methods outside the class while implementing the concept of inheritance. These are three types of access modifiers:
👻Public
👻Private
👻Protected
Note: These access specifiers in Python are not rigid. You still can access all the variables instead of having private or protected specifiers over them.
👋Public specifier
By default, all the variables and methods are public in Python. All Variables having a name as self.variableName can be publicly accessed.
class demo:
def __init__(name):
self.name = name
demoObj = demo("ABD")
print(demoObj.name)
👋Private specifier
Theoretically, private members and methods cannot be accessed outside of class. Private variables are written with a name prefixed with __
class demo:
def __init__(name):
self.__name = name
def __show(self):
print("hey")
demoObj = demo("ABD")
print(demoObj.__name) --> This will be throwing an error
🌼But in python we can still access it using concept of name mangling as
print(demoObj._demo__name)-->This will work
🍟If we will write something like:
print(demoObj.__dir__) -->This will give me list of all the methods that can be run on this instance
OR
print(dir(demoObj))
🥗Name Mangling is a concept used to protect class private attributes from being accidentally overwritten by subclasses.
👋Protected specifier
This ensures that protected class members and functions will only be accessible inside the class and its subclass. They are named by prefixing the name with a single underscore.
class demo:
def __init__(name):
self._name = name
def _show(self):
print("hey")
class demoChild(demo):
obj = demo("gfg")
print(obj._name)
🥙Static Methods in Python
These methods belong to a class rather than an instance of a class. Defined using the @staticmethod decorator and do not have access to the instance of the class i.e. self keyword. These are called directly with className.You do not need to create an instance for calling these functions however if you want you can.
class demo:
def __init__():
self.num = 10
@staticmethod
def multiply(a, b):
return a*b
print(demo.multiply(2, 3))
🍭Instance v/s class Variables
Class variables are used to store information common to all the instances.
class demoClass:
demoClassVar=2
def __init__(self):
self.name = "abc"
print(demoClass.demoClassVar)
🍷Class Methods
Class methods are bound to the class and not to the instance of the class. They are defined using the @classmethod decorator followed by the function definition. In the function, the first argument will always be representing the class.
class demo:
platform="facebook"
@classmethod
def changePlatform(cls, newPlatform):
cls.platform = newPlatform
obj = demo()
print(obj.changePlatform("medium"))
#Now medium will be updated as platform in demo class for all the instances.It's not like that it will change only for this instance.
🍟Class methods as Alternative Constructors
class Demo:
def __init__(name, age):
self.name = name
self.age = age
@classmethod
def from_string(cls, string)
name,age = string.split("-")
return cls(name, int(age))
Demo.from_string("Abc-22")
🍿The dir() method
Returns the list of all attributes and methods available for an object.
x = [9,8,7]
print(dir(x))
🧊The __dict__ attribute
This returns a dictionary representation of an object’s attribute.
class demo:
def __init__(a,b):
self.a = a
self.b=b
d = demo(2,30)
print(d.__dict__)
🍚Super Keyword
The super keyword is used to refer to the parent class. It is helpful when a child class wants to call the method of the parent class.
Note: If through a child class, you are calling a method that is not present in the child class but is present in the parent class then it will automatically be calling the method of the parent class.
class demo:
def parentDemo:
print("Hey! Buddy")
class childDemo(demo):
super().parentDemo()
#This concept comes handy when you want to use constructor of parent class.
🍳 Magic/Dunder Methods
These methods are surrounded by double underscores around their name.
class demo:
name="abcd"
def __len__(self):
return len(self.name)
def __str__(self):
return f"The name is {self.name}"
def __call__(self):
print("Hello! Bro")
obj = Demo()
print(len(obj))-->Since it's a magic method so see we have called this in a different way.
obj() --> possible because of __call__ method
#Some dunder methods are
🍭__init__ method
🍭__str__ and __repr__ method
🍭__len__ method
🍭__call__ method -->makes an object callable
🌷Method Overriding
This allows us to redefine a method of parent class into child class.
class demo:
def sayHi():
print("Bye!"
class childDemo(demo):
def sayHi():
print("Hi!")
obj = childDemo()
print(obj.sayHi())
🌺Single Inheritance
The class inherits properties and behaviors from a single-parent class.
class childClass(ParentClassName):
#class body
🧅Multiple Inheritance
Allows a class to inherit methods and attributes from multiple classes.
class A:
def sayHello():
print("Hello from class A!")
class B:
def sayHello():
print("Hello from class B!")
class C(A,B):
def sayBye():
print("Bye")
obj = C()
print(obj.sayHello)-->It will run sayHello Function of A class because it is inherited first.
#Method resolution order
print(C.mro())-->It will print the order in which function will be searched.
🥨Multilevel Inheritance
In this inheritance, a derived class is inherited from another derived class.
class Base:
#class Body
class derived1(Base):
#class body
class derived2(Base):
#class body
🍂Walrus Operator
This is an addition to Python 3.8. It allows us to assign a value to a variable within an expression.
a = True
print(a:=False)-->This is how walrus operator works
numbers = [1,2,3]
while(n:=len(numbers)) > 0:
print(numbers.pop())
🥀Generators in Python
These are a special type of function that allows us to create a generator object, which in turn helps in generating value one by one on the fly. The yield statement is used in the generators. It returns a value from the generator and suspends the execution of the function until the next value is requested.
def myGenerator():
for i in range(5)
yield i
gen = myGenerator()
print(next(gen)
for j in gen:
print(j)
⚡Function Caching in Python
This is a technique for improving the performance of a program by storing the results of a function call. This can be achieved through functools.lru_cache decorator. This cache will be cleared once you re-run the program.
import functools
@functools.lru_cache(maxsize=None)
def myFunc():
//function body
So, this sums up this article. I would like to extend my heartfelt gratitude to the “Code With Harry” YouTube channel for being an invaluable source of knowledge and learning on the journey to mastering Python programming. Hope you enjoyed the read! Happy Coding:)