Python Notes Unrestricted
Python Notes Unrestricted
Python is a high-level, interpreted programming language known for its simplicity and readability. It
is widely used in a variety of fields, including web development, data science, artificial intelligence,
scientific computing, automation, and more. Here are some key features of Python:
Easy Syntax
Interpreted Language
Object-Oriented programming
Extensive Libraries
Cross-Platform.
print("Hello, World!")
Multi-line comment:
"""
This is a
Multi-line comment.
"""
Data Types
Variable
Valid Characters:
Variable names can consist of letters (both uppercase and lowercase), digits (0-9), and
underscores (_).
The first character must be a letter or an underscore. It cannot start with a digit.
■ No Special Characters:
Variable names are case-sensitive. For example, variable, Variable, and VARIABLE are considered
three different variables.
■ Length:
While there is no strict limit on the length of variable names, it’s best practice to keep them
reasonably short yet descriptive for readability.
■ No Reserved Keywords:
Variable names cannot be the same as C reserved keywords (e.g., int, return, if, while, etc.).
EXAMPLE
■ age
■ total_sum
■ username
■ score1
INVALID EXAMPLE
Variable Decleration
Syntax
Variable=value
Example:
age = 30 # Integer
Operators
(condition) ? : ;
if (condition) else
Conditional Statement:
if statement
x=5
if x > 0:
Example
x=0
if x > 0:
print("x is positive")
elif x == 0:
else statement
Example
x = -1
if x > 0:
print("x is positive")
elif x == 0:
print("x is zero")
else:
Looping Statements:
while loop
Example
# Print numbers 1 to 5
x=1
while x <= 5:
print(x)
for loop:
print(i)
Example:
Break
for x in range(10):
if x == 5:
print(x)
continue
for x in range(5):
if x == 3:
print(x)
pass
for x in range(5):
if x == 3:
else:
print(x)
Nested if:
x=5
if x > 0:
if x == 5:
Number programming
1. Reverse of Number
number = 12345
reversed_number = 0
[Link] Number
number = 5
result = 1
[Link] of n numbers
sum_of_numbers = 0
[Link] series
a = -1
b=1
print(c)
[Link] of loop
# Original range
n=5
n = 12345
# Last digit (using modulus)
last_digit = n % 10
first_digit = n
first_digit = first_digit // 10
if n % 2 == 0:
print(f"{n} is even")
else:
print(f"{n} is odd")
if n <= 1:
is_prime = False
else:
if n % i == 0:
is_prime = False
if is_prime:
else:
[Link] program
n = 12321
original_n = n
reversed_n = 0
while n > 0:
reversed_n = reversed_n * 10 + n % 10
n //= 10
if original_n == reversed_n:
else:
[Link] number
Example:
6=1+2+3
divisors_sum = 0
if n % i == 0:
divisors_sum += i
if divisors_sum == n:
else:
is_perfect_square = False
if i * i == n:
is_perfect_square = True
if is_perfect_square:
print(f"{n} is a perfect square.")
else:
[Link] of PrimeNumbers
if n <= 1:
is_prime = True
if n % i == 0:
is_prime = False
break
if is_prime:
[Link] Number
Example:
N=3
successor = n + 1
is_perfect_square = False
if i * i == successor:
is_perfect_square = True
break
if is_perfect_square:
[Link] number
Example:
1!+4!+5!=1+24+120=145
original_n = n
sum_of_factorials = 0
while n > 0:
factorial *= i
sum_of_factorials += factorial
if sum_of_factorials == original_n:
else:
[Link] Number
original_n = n
digit_sum = 0
while n > 0:
digit_sum += n % 10
n //= 10
if original_n % digit_sum == 0:
else:
print(f"{original_n} is not a Harshad Number.")
[Link] number
A Spy Number is a number where the sum of its digits equals the product of its digits. For example:
1124 is a Spy Number because 1+1+2+4=8 and 1×1×2x4=8
digit_sum = 0
digit_product = 1
while n > 0:
digit = n % 10
digit_sum += digit
digit_product *= digit
n //= 10
if digit_sum == digit_product:
else:
LIST
# LIST IS MUTABLE
[Link] OF LIST
print(type(mylist))
print(len(thislist))
print(thislist[-1])
print(thislist[2:5])
6.1
print(thislist[:4])
6.2
print(thislist[2:])
print(thislist[-4:-1])
thislist[1] = "blackcurrant"
print(thislist)
8.1
print(thislist)
[Link](2, "watermelon")
print(thislist)
[Link] FUNCTION
[Link]("orange")
print(thislist)
[Link] FUNCTION
[Link](b)
print(a)
[Link] FUNCTION
[Link]("banana")
print(thislist)
[Link] FUNCTION
[Link](1)
print(thislist)
[Link] FUNCTION
del thislist[0]
print(thislist)
[Link] FUNCTION
[Link]()
print(thislist)
for x in thislist:
print(x)
newlist = []
for x in fruits:
if "a" in x:
[Link](x)
print(newlist)
[Link] OF LIST
[Link]()
print(thislist)
[Link] OF LIST
[Link]()
print(thislist)
[Link] OF LIST
mylist = [Link]()
print(mylist)
[Link] OF LIST
list2 = [1, 2, 3]
print(list3)
LIST METHODS
extend()-Add the elements of a list (or any iterable), to the end of the current list
index()-Returns the index of the first element with the specified value
TUPLES
#TUBLE IS IMMUTABLE
[Link] OF TUPLES
tuple2 = (1, 5, 7, 9, 3)
print(tuple)
print(type(mytuple))
print(len(thistuple))
print(thistuple[1])
#ACCESSING
[Link]
[Link] INDEXING
[Link]
if "apple" in thistuple:
print("Yes, 'apple' is in the fruits tuple")
[Link] TUPLE
Once a tuple is created, you cannot change its values. Tuples are unchangeable, or immutable as it
also is called.
But there is a workaround. You can convert the tuple into a list, change the list, and convert the list
back into a tuple.
y = list(x)
y[1] = "kiwi"
x = tuple(y)
print(x)
[Link] FUNCTION
y = list(thistuple)
[Link]("orange")
thistuple = tuple(y)
[Link] OF TUPLE
tuple2 = (1, 2, 3)
print(tuple3)
mytuple = fruits * 2
print(mytuple)
[Link] FUNCTION
y = list(thistuple)
[Link]("apple")
thistuple = tuple(y)
[Link] FUNCTION
del thistuple
print(thistuple)
[Link] TUPLE
#e are also allowed to extract the values back into variables. This is called "unpacking":
print(green)
print(yellow)
print(red)
print(green)
print(yellow)
print(red)
for x in thistuple:
print(x)
[Link] METHOD
index()-Searches the tuple for a specified value and returns the position of where it was found
SET
[Link] OF SET
set2 = {1, 5, 7, 9, 3}
print(type(myset))
print("banana" in thisset)
OR
[Link]("orange")
print(thisset)
[Link](tropical)
print(thisset)
[Link]("banana")
print(thisset)
[Link]("banana")
print(thisset)
[Link] FUNCTION
x = [Link]()
[Link] FUNCTION
[Link]()
print(thisset)
[Link] FUNCTION
del thisset
print(thisset)
[Link] IN SET
for x in thisset:
print(x)
[Link] SETS
12.1 UNION
#UNION OPERATOR--> |
set2 = {1, 2, 3}
set2 = {1, 2, 3}
print(myset)
print(myset)
12.2 INTERSECTION
#INTERSECTION OPERATOR--->&
print(set3)
print(set3)
12.3 DIFFERENCE
#DIFFERENCE OPERATOR-->-
set3 = [Link](set2)
print(set3)
print(set3)
set3 = set1.symmetric_difference(set2)
print(set3)
print(set3)
[Link] METHOD
DICTIONARIES
[Link] OF DICTIONARIES
thisdict = {
"brand": "Ford",
"electric": False,
"year": 1964,
print(thisdict)
[Link] OF DICT
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
print(type(thisdict))
[Link] OF DICT
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
print(thisdict["brand"])
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964,
"year": 2020
print(len(thisdict))
[Link] GET A KEY IN DICT
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
x = [Link]()
print(x)
car = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
x = [Link]()
car["color"] = "white"
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
thisdict["year"] = 2018
print(thisdict)
[Link] FUNCTION
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
[Link]({"year": 2020})
print(thisdict)
[Link] FUNCTION
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
[Link]("model")
print(thisdict)
[Link] FUNCTION
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
[Link]()
print(thisdict)
[Link] FUNCTION
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
del thisdict["model"]
print(thisdict)
[Link] FUNCTION
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
[Link]()
print(thisdict)
[Link] IN DICT
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
for x in thisdict:
print(x)
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
for x in [Link]():
print(x)
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
for x in [Link]():
print(x)
[Link] DICT
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
mydict = [Link]()
print(mydict)
[Link] DICT
myfamily = {
"child1" : {
"name" : "Emil",
"year" : 2004
},
"child2" : {
"name" : "Tobias",
"year" : 2007
},
"child3" : {
"name" : "Linus",
"year" : 2011
print(myfamily)
ARRAY
[Link] OF ARRAY
print(cars)
x = cars[0]
print(x)
x = len(cars)
print(x)
[Link] IN ARRAY
cars = ["Ford", "Volvo", "BMW"]
for x in cars:
print(x)
[Link] FUNCTION
[Link]("Honda")
print(cars)
[Link] FUNCTION
[Link](1)
print(cars)
[Link] FUNCTION
[Link]("Volvo")
print(cars)
[Link] METHODS
extend() Add the elements of a list (or any iterable), to the end of the current list
index() Returns the index of the first element with the specified value
Array programming
Reverse of Array
arr = [1, 2, 3, 4, 5]
reversed_arr = arr[::-1]
print("Reversed array using slicing:", reversed_arr)
# Example array
arr = [1, 2, 3, 4, 5]
start = 0
end = len(arr) - 1
start += 1
end -= 1
Sum of Array
# Example array
arr = [1, 2, 3, 4, 5]
total_sum = 0
# Example array
max_val = arr[0]
min_val = arr[0]
max_val = num
min_val = num
arr = [1, 2, 2, 3, 4, 4, 5, 5]
unique_arr = []
unique_arr.append(num)
# Example array
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
sum_odds = 0
sum_odds += num
# Example array
n = len(arr)
for i in range(n):
# Example array
n = len(arr)
positive_index = 0
for i in range(n):
if arr[i] >= 0:
arr[positive_index] = arr[i]
positive_index += 1
for i in range(n):
if arr[i] < 0:
arr[positive_index] = arr[i]
positive_index += 1
# Example array
arr = [1, 2, 3, 4, 5]
k=2
n = len(arr)
k=k%n
# Step 2: Rotate the array using a simple loop
for _ in range(k):
last_element = arr[n-1]
arr[i] = arr[i-1]
arr[0] = last_element
def majority_element(arr):
# Initialize variables
arr_dict = {}
majority_element = None
for i in arr:
arr_dict[i] = arr_dict.get(i, 0) + 1
if len(set(arr_dict.values())) == 1:
return None
if majority_element is None:
majority_element = key
continue
majority_element = key
return majority_element
# Example array
#arr = [1, 2, 3, 4, 1, 1, 1, 1]
arr = [3, 3, 4, 2, 4, 4, 2, 4, 4, 5, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1]
major_element = majority_element(arr)
if major_element:
else:
STRING
print("Hello")
print('Hello')
a = "Hello"
print(a)
STRING QUOTES
print("It's alright")
MULTILINE STRING
print(a)
OR
print(a)
ACCESSING OF STRING
a = "Hello, World!"
print(a[6])
for x in "banana":
print(x)
CHECK WEATHER STRING IS PRESENT OR NOT
INFUNCTION
if "free" in txt:
NOT IN FUNCTION
STRING SLICING
b = "Hello, World!"
print(b[:5])
[Link] INDEXING
2. NEGATIVE INDEXING
[Link] FUNCTION
a = "Hello, World!"
print([Link]())
[Link] FUNCTION
a = "Hello, World!"
print([Link]())
[Link] FUNCTION
[Link] FUNCTION
a = "Hello, World!"
print([Link]("H", "J"))
[Link] FUNCTION
a = "Hello, World!"
a = "Hello"
b = "World"
c=a+""+b
print(c)
STRING FORMAT
age = 36
print(txt)
1. FORMAT
age = 36
print(txt)
price = 59
print(txt)
2.1
print(txt)
ESCAPE CHARACTER
print(txt)
String Programming
s = "Hello"
length = 0
for char in s:
length += 1
s = "Hello"
char_to_search = "o"
found = False
for char in s:
if char == char_to_search:
found = True
break
s = "Hello"
start = 1
end = 4
substring += s[i]
s = "Hello World"
char_to_count = "o"
count = 0
for char in s:
if char == char_to_count:
count += 1
s = "Hello World"
old_char = "o"
new_char = "x"
for char in s:
if char == old_char:
result += new_char
else:
result += char
Converting Uppercase
s = "hello"
result = ''
for char in s:
else:
result += char
Converting Lowercase
s = "HELLO"
result = ''
for char in s:
else:
result += char
String palindrome
s = "madam"
if s[left] != s[right]:
is_palindrome = False
break
left += 1
right -= 1
String Palindrome
s = "madam"
if s == s[::-1]:
else:
Split Function
s = "Hello World"
words = []
for char in s:
if word:
[Link](word)
else:
word += char
[Link](word)
s1 = "Hello"
s2 = "hello"
are_equal = True
if len(s1) != len(s2):
are_equal = False
else:
for i in range(len(s1)):
if s1[i] != s2[i]:
are_equal = False
break
FUNCTIONS
def print_hello():
print("Hello!")
print_hello()
def get_five():
return 5
result = get_five()
print(result) # Output: 5
return a * b
result = multiply(3, 4)
print(result) # Output: 12
1.4 NO RETURN WITH ARGS
def greet_person(name):
print(f"Hello, {name}!")
LAMBDA
Syntax
EXAMPLE:
x = lambda a: a + 10
print(x(5))
x = lambda a, b : a * b
print(x(5, 6))
The power of lambda is better shown when you use them as an anonymous function inside another
function.
Say you have a function definition that takes one argument, and that argument will be multiplied
with an unknown number
EXAMPLE:
def myfunc(n):
return lambda a : a * n
x = myfunc(2)
print(x(11))
[Link] EXAMPLE
def myfunc(n):
return lambda a : a * n
mydoubler = myfunc(2)
mytripler = myfunc(3)
print(mydoubler(11))
print(mytripler(11))
Modularity:
Modularity: OOP allows you to break down a complex problem into smaller, manageable pieces by
creating classes and objects
Maintainability: Code is more organized and easier to manage, making updates and maintenance
simpler.
Scalability: OOP systems are easier to extend as new objects and functionalities can be added
without affecting existing code.
CLASS
A class is a blueprint or template for creating objects. It defines the properties (also called attributes
or fields) and behaviors (also called methods or functions) that the class will have.
Syntax:
class class_name:
OBJECT
[Link] or attributes
[Link] or methods
Rule 2:
Syntax:
object_name = ClassName(arguments)
Example :
class MyClass:
x=5
print(MyClass.x)
obj = MyClass()
print(obj.x)
Constructor
a constructor is a special method that is automatically called when an object (instance) of a class is
created. The constructor is used to initialize the object's attributes (properties) and set up any
necessary state for the object.
Syntax:
class ClassName:
self.attribute1 = value1
self.attribute2 = value2
Example:
class Car:
def display_info(self):
Destructor in Python
A destructor is a special method that is called when an object is about to be destroyed. It allows you
to clean up any resources (like closing files or releasing connections) before the object is deleted.
It is automatically called when an object’s reference count reaches zero, which happens when there
are no more references to that object.
Example of Destructor
class Person:
[Link] = name
[Link] = age
def __del__(self):
print(f"Person {[Link]} is being destroyed.")
In this example:
The __del__ method is the destructor. It prints a message when the object is being destroyed.
The del statement explicitly deletes the object, triggering the destructor.
Self is a reference to the current instance of the class. This means when you create an object from
a class, self allows you to access the object's attributes and methods.
Why selfkeyword
Distinguishing Between Instance and Local Variables: self distinguishes between instance variables
(those tied to the object) and local variables in methods. Without self, Python would treat any
variable defined within the method as a local variable that is not tied to an instance.
Access modifiers
Encapsulation
Inheritance
Polymorphism
Abstraction
Encapsulation
Encapsulation is nothing but hideing or binding a data from the user or wraping data from the user
to achive encapsulation we must use class as private by using private keyword we are going to hide
a data from the user if suppose some other classes want to use a private hided data there is two
method
Two Method
Getter function
Setter function
The process of using the getter method and setter method is called data binding method
[Link] BAG
[Link]
If combinations of medicine are variables and methods then the capsule will act as a class and the
whole process is called Encapsulation
Example:
class Person:
def get_name(self):
return self.__name
if len(name) > 0:
self.__name = name
else:
def get_age(self):
return self.__age
if age >= 0:
self.__age = age
else:
print(person1.get_age()) # Outputs: 30
person1.set_name("Bob")
person1.set_age(35)
print(person1.get_age()) # Outputs: 35
Inheritance
Inheritance allows a class to inherit attributes and methods from another class.
Types:
Multiple Inheritance: A class inherits from more than one base class.
Multilevel Inheritance: A class inherits from another class, which is derived from another class.
5.1
Single Inheritance
EXAMPLE:
class Animal:
def speak(self):
class Dog(Animal):
def weak(self):
return "Woof!"
dog = Dog()
print([Link]()) # Output: Woof!
5.2
Multiple Inheritance
A class inherits from more than one base class. The derived class has access to the methods and
attributes of all its parent classes.
EXAMPLE:
class Animal:
def speak(self):
class Pet:
def play(self):
return "Playing"
def speak(self):
return "Woof!"
dog = Dog()
5.3
Multilevel Inheritance
A class inherits from a base class, and another class inherits from this derived class.
EXAMPLE:
class Animal:
def speak(self):
class Mammal(Animal):
def has_hair(self):
return True
class Dog(Mammal):
def speak(self):
return "Woof!"
dog = Dog()
5.4
Hierarchical Inheritance
Multiple classes inherit from a single base class. Each derived class can have its own additional
methods and attributes.
EXAMPLE:
class Animal:
def speak(self):
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
dog = Dog()
cat = Cat()
Super Function
The super() function is used to call methods from a parent class from within a method in a child
class.
EXAMPLE:
class Base:
def __init__(self):
print("Base init")
class Derived(Base):
def __init__(self):
print("Derived init")
d = Derived()
# Output:
# Base init
# Derived init
POLYMORPHISM
Polymorphism allows methods to do different things based on the object it is acting upon. It means
"many forms" and can be implemented using method overriding or method overloading.
3. Operator Overloading
Method Overriding
Method overriding occurs when a subclass provides a specific implementation for a method that is
already defined in its superclass. The new implementation in the subclass replaces the one in the
superclass. This is useful when you want to modify or extend the behavior of a method inherited
from a parent class.
EXAMPLE:
class Animal:
def make_sound(self):
class Dog(Animal):
def make_sound(self):
print("Woof!")
class Cat(Animal):
def make_sound(self):
print("Meow!")
# Create instances
animal = Animal()
dog = Dog()
cat = Cat()
Method Overloading
Method overloading refers to defining multiple methods with the same name but with different
parameters (e.g., different number of arguments or different types of arguments). Unlike some other
programming languages like Java or C++, Python does not support method overloading directly.
Instead, you can use default arguments, variable-length argument lists, or keyword arguments to
achieve similar functionality.
Example:
class MethodOverloading:
def fun(self,a=None,b=None,c=None):
return a+b+c
return a+b
else:
return a
object=MethodOverloading()
class MethodOverloading:
def fun(self,*args):
sum=0
for i in args:
sum+=i
object=MethodOverloading()
[Link](10)
[Link](10,20)
[Link](10,20,30)
[Link](10,20,30,40)
Abstraction
Abstraction involves hiding the complex implementation details and showing only the essential
features of an object.
In Python, abstraction can be achieved using abstract base classes (ABCs) from the abc module.
Abstract Base Class: A class that contains one or more abstract methods. An abstract method is a
method that is declared but contains no implementation. Subclasses must implement these
methods.
Example:
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
[Link] = width
[Link] = height
def area(self):
# Creating an instance
print([Link]()) # Output: 50
class Polygon(ABC):
@abstractmethod
def noofsides(self):
pass
class Triangle(Polygon):
class Pentagon(Polygon):
def noofsides(self):
class Hexagon(Polygon):
def noofsides(self):
class Quadrilateral(Polygon):
def noofsides(self):
# Driver code
R = Triangle()
[Link]()
K = Quadrilateral()
[Link]()
R = Pentagon()
[Link]()
K = Hexagon()
[Link]()
Summary
EXCEPTION HANDLING
#The finally block gets executed no matter if the try block raises any errors or not:
try:
print(x)
except:
finally:
try:
except SomeExceptionType:
else:
finally:
Example:
try:
except ZeroDivisionError:
except TypeError:
Example:
try:
Types of Error
1. Syntax Errors
1. ZeroDivisionError
x = 10 / 0 # Raises ZeroDivisionError
2. IndexError
lst = [1, 2, 3]
3. ValueError
Raised when a function receives an argument of the right type but inappropriate value.
4. KeyError
my_dict = {"a": 1}
5. TypeError
"hello" + 5 # Raises TypeError because you can't add a string and an integer
6. FileNotFoundError
7. AttributeError
x = 10
8. NameError
a = "hello" + 10 # TypeError
3. Handling Errors
Errors can be caught and handled using exception handling mechanisms like `try`, `except`, `else`,
and `finally`. This allows the program to continue running even if an error occurs.
try:
result = 10 / 0
except ZeroDivisionError:
ADVANCE PYTHON
Map function
the map() function is a built-in function that allows you to apply a given function to all items in an
iterable (like a list or a tuple) and return a map object (which is an iterator).
This can be useful for transforming data in a concise and readable way.
the result of map() is an iterator, so you need to convert it to a list (or another iterable type) to see
the results.
the map() function is a powerful tool for functional programming in python, allowing for clean and
efficient transformations of data within iterables.
SYNTAX:
EXAMPLE:
def square(x):
return x ** 2
numbers = [1, 2, 3, 4, 5]
squared_numbers_list = list(squared_numbers)
[Link]
itertools is a Python module that provides a collection of fast, memory-efficient tools for working with
iterators.
ITERTOOLS FUNCTIONS
2.1 REPEAT
repeat_example = [Link]('Hello', 3)
2.3 COMBINATION
2.4 PERMUTATION
print(list(perm_example)) # Output: [('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')]
2.5 PRODUCT
print(list(prod_example)) # Output: [(1, 'A'), (1, 'B'), (2, 'A'), (2, 'B')]
DECORATORS
Decorators in Python are a powerful and expressive way to modify or enhance functions or
methods.
They allow you to wrap another function to extend its behavior without permanently modifying it.
Decorators are often used for logging, access control, caching, and other cross-cutting concerns.
EXAMPLE:
def greet_decorator(func):
print("Hello!")
@greet_decorator
def say_name(name):
say_name("Alice")
GENERATORS
Generators are a powerful feature in Python that allow for efficient iteration over sequences of data.
They provide a convenient way to handle large datasets, lazy evaluation, and simpler code
structures.
By using yield, you can create functions that generate values on the fly, making your programs
more efficient and responsive. If you have any specific questions or need further examples, feel free
to ask!
EXAMPLE:
def square_numbers(n):
for i in range(n):
squares = square_numbers(5)
for x in squares:
print(x)
COLLECTIONS
[Link]:
# Example
counter = Counter(text)
print(counter) # Output: Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
[Link] DICT:
# Example
d = defaultdict(int)
d['a'] += 1
print(d['a']) # Output: 1
[Link] DICT:
# Example
od = OrderedDict()
od['a'] = 1
od['b'] = 2
# Example
dq = deque()
[Link]('a')
[Link]('b')
[Link]('c')
[Link]()
CHAIN MAP:
# Example
Named Tuple:
p = Point(1, 2)
print(p) # Output: Point(x=1, y=2)
print(p.x) # Output: 1
Stack (LIFO)
class Stack:
def __init__(self):
[Link] = []
[Link](item)
def pop(self):
if not self.is_empty():
return [Link]()
return None
def peek(self):
def is_empty(self):
return len([Link]) == 0
# Usage example
stack = Stack()
[Link](1)
[Link](2)
print([Link]()) # Output: 2
THREAD
import threading
import time
class MyThread([Link]):
def run(self):
for i in range(5):
[Link](1)
thread = MyThread()
[Link]()
Data Structures and Algorithms (DSA) is a fundamental part of Computer Science that teaches you
how to think and solve complex problems systematically.
Using the right data structure and algorithm makes your program run faster, especially when
working with lots of data.
Although Data Structures and Algorithms is actually not specific to any programming language, you
should have a basic understanding of programming in one of programming languages:
We structure data in different ways depending on what data we have, and what we want to do with
it.
Data structures give us the possibility to manage large amounts of data efficiently for uses such as
large databases and internet indexing services.
Primitive Data Structures are basic data structures provided by programming languages to
represent single values, such as integers, floating-point numbers, characters, and booleans.
Abstract Data Structures are higher-level data structures that are built using primitive data types
and provide more complex and specialized operations. Some common examples of abstract data
structures include arrays, linked lists, stacks, queues, trees, and graphs.
Algorithm
Algorithm examples:
Array
We already learned
Bubble Sort
Step 2: We look at the two first values. Does the lowest value come first? Yes, so we don't need to
swap them.
Step 3: Take one step forward and look at values 12 and 9. Does the lowest value come first? No.
[7, 12, 9, 11, 3]
Example:
n = len(my_array)
for i in range(n-1):
for j in range(n-i-1):
Selection Sort
[ 7, 12, 9, 11, 3]
Step 2: Go through the array, one value at a time. Which value is the lowest? 3, right?
[ 7, 12, 9, 11, 3]
[ 3, 7, 12, 9, 11]
Step 4: Look through the rest of the values, starting with 7. 7 is the lowest value, and already at the
front of the array, so we don't need to move it.
[ 3, 7, 12, 9, 11]
Step 5: Look through the rest of the array: 12, 9 and 11. 9 is the lowest value.
[ 3, 7, 12, 9, 11]
[ 3, 7, 9, 12, 11]
Step 7: Looking at 12 and 11, 11 is the lowest.
[ 3, 7, 9, 12, 11]
[ 3, 7, 9, 11, 12]
Example:
n = len(my_array)
for i in range(n-1):
min_index = i
min_index = j
min_value = my_array.pop(min_index)
my_array.insert(i, min_value)
Linked List
A linked list consists of nodes with some sort of data, and a pointer, or link, to the next node.
Example:
class Node:
[Link] = data
[Link] = None
node1 = Node(3)
node2 = Node(5)
node3 = Node(13)
node4 = Node(2)
[Link] = node2
[Link] = node3
[Link] = node4
currentNode = node1
while currentNode:
print("null")
Example
class Node:
[Link] = data
[Link] = None
[Link] = None
node1 = Node(3)
node2 = Node(5)
node3 = Node(13)
node4 = Node(2)
[Link] = node2
[Link] = node1
[Link] = node3
[Link] = node2
[Link] = node4
[Link] = node3
print("\nTraversing forward:")
currentNode = node1
while currentNode:
currentNode = [Link]
print("null")
print("\nTraversing backward:")
currentNode = node4
while currentNode:
currentNode = [Link]
print("null")
Example:
class Node:
[Link] = data
[Link] = None
node1 = Node(3)
node2 = Node(5)
node3 = Node(13)
node4 = Node(2)
[Link] = node2
[Link] = node3
[Link] = node4
currentNode = node1
startNode = node1
currentNode = [Link]
currentNode = [Link]
class Node:
[Link] = data
[Link] = None
[Link] = None
node1 = Node(3)
node2 = Node(5)
node3 = Node(13)
node4 = Node(2)
[Link] = node2
[Link] = node1
[Link] = node3
[Link] = node2
[Link] = node4
[Link] = node3
print("\nTraversing forward:")
currentNode = node1
startNode = node1
currentNode = [Link]
currentNode = [Link]
print("\nTraversing backward:")
currentNode = node4
startNode = node4
currentNode = [Link]
while currentNode != startNode:
currentNode = [Link]
Stack(LIFO)
Pop: Removes and returns the top element from the stack.
Example:
stack = []
# Push
[Link]('A')
[Link]('B')
[Link]('C')
# Pop
element = [Link]()
# Peek
topElement = stack[-1]
# isEmpty
# Size
print("Size: ",len(stack))
Queues(FIFO)
A queue is a data structure that can hold many elements.
Dequeue: Removes and returns the first (front) element from the queue.
Example:
queue = []
# Enqueue
[Link]('A')
[Link]('B')
[Link]('C')
# Dequeue
element = [Link](0)
# Peek
frontElement = queue[0]
# isEmpty
# Size
#Python
Dequeue
# Example
dq = deque()
[Link]('a')
[Link]('b')
[Link]('c')
print(dq) # Output: deque(['c', 'a', 'b'])
[Link]()
Hash Table
The reason Hash Tables are sometimes preferred instead of arrays or linked lists is because
searching for, adding, and deleting data can be done really quickly, even for large amounts of data.
In a Linked List, finding a person "Bob" takes time because we would have to go from one node to
the next, checking each node, until the node with "Bob" is found.
And finding "Bob" in an Array could be fast if we knew the index, but when we only know the name
"Bob", we need to compare each element (like with Linked Lists), and that takes time.
With a Hash Table however, finding "Bob" is done really fast because there is a way to go directly to
where "Bob" is stored, using something called a hash function.
Example:
def hash_function(value):
sum_of_chars = 0
sum_of_chars += ord(char)
return sum_of_chars % 10
Heap
A heap is a binary tree used to represent a priority queue. You can use the heapq module in Python
to implement heaps.
import heapq
heap = [1, 3, 2, 5, 4]
[Link](heap)
# Adding an element
[Link](heap, 0)
print([Link](heap)) # Output: 0
Searching Algorithm
Linear Search
def linear_search(arr, target):
if value == target:
arr = [5, 3, 8, 6, 7]
result = linear_search(arr, 8)
print(result) # Output: 2
Binary Search
if arr[mid] == target:
else:
arr = [1, 3, 5, 7, 9]
result = binary_search(arr, 7)
print(result) # Output: 3
if visited is None:
visited = set()
[Link](node)
graph = {
'D': ['B'],
visited = set()
queue = deque([start])
[Link](start)
while queue:
node = [Link]()
[Link](neighbor)
[Link](neighbor)
graph = {
'D': ['B'],
Sorting Algorithms
Bubble Sort
def bubble_sort(arr):
n = len(arr)
for i in range(n):
swapped = False
swapped = True
if not swapped:
return arr
arr = [5, 1, 4, 2, 8]
Selection Sort
def selection_sort(arr):
n = len(arr)
for i in range(n):
min_idx = i
min_idx = j
return arr
Insertion Sort
def insertion_sort(arr):
key = arr[i]
j = i-1
arr[j+1] = arr[j]
j -= 1
arr[j+1] = key
return arr
4. Merge Sort
def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) // 2
left_half = arr[:mid]
right_half = arr[mid:]
merge_sort(left_half)
merge_sort(right_half)
i=j=k=0
arr[k] = left_half[i]
i += 1
else:
arr[k] = right_half[j]
j += 1
k += 1
arr[k] = left_half[i]
i += 1
k += 1
arr[k] = right_half[j]
j += 1
k += 1
return arr
Quick Sort
def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
6. Heap Sort
import heapq
def heap_sort(arr):
arr = [5, 3, 8, 6, 7]
Tree Algorithm
Binary tree
class Node:
[Link] = None
[Link] = key
def inorder(root):
if root:
inorder([Link])
inorder([Link])
root = Node(1)
[Link] = Node(2)
[Link] = Node(3)
[Link] = Node(4)
[Link] = Node(5)
inorder(root) # Output: 4 2 5 1 3
class BSTNode:
[Link] = None
[Link] = None
[Link] = key
if not root:
return BSTNode(key)
else:
return root
root = BSTNode(50)
insert(root, 30)
insert(root, 20)
insert(root, 40)
insert(root, 70)
insert(root, 60)
insert(root, 80)