Python - Programming - Ipynb - Colab
Python - Programming - Ipynb - Colab
ipynb - Colab
Python is a high-level, interpreted programming language known for its readability and simplicity. It’s used in web development, data
analysis, artificial intelligence, scientific computing, and more.
Abstracted from Machine Code: High-level languages are far removed from the binary machine code that the computer's processor
understands. They use natural language elements and abstract away the hardware details.
Readable and Writable: They are designed to be readable and writable by humans. This means they use syntax and keywords that are
intuitive and closer to human languages.
Productivity: High-level languages enable programmers to write programs more quickly and with fewer errors, making them more
productive. Examples include Python, Java, and C++.
Interpreted Language
Execution by Interpreter: Interpreted languages are executed line-by-line by an interpreter at runtime, rather than being compiled into
machine code before execution. The interpreter translates each high-level instruction into machine code on the fly.
Platform Independence: Because the interpreter translates the code at runtime, the same high-level code can be run on different types of
hardware and operating systems without modification, as long as the appropriate interpreter is available.
Ease of Use and Flexibility: Interpreted languages often allow more flexibility with features like dynamic typing and dynamic execution of
code. This can make them easier to use for rapid development and prototyping.
# 1. Indentation
if 5 > 2:
print("Five is greater than two.") # This line is indented, so it's inside the if block
"""if 5 > 2:
print("Five is greater than two.")"""
# 2. Comments
Hello, World!
"""
This is a multi-line comment or docstring.
It can span multiple lines.
"""
print("Hello, World!")
Hello, World!
# 3. Readability
my_variable = 10
def my_function():
pass
dog = 'doberman'
# This is an example of a long comment that might need to be wrapped and fit within the 79 character limit
[Link] 1/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
# 4. Spacing
# Whitespace in Expressions and Statements
# Avoid extraneous whitespace.
# Correct:
x = 1
y = x + 2
print(y)
# Wrong:
x=1
y = x+2
print(y)
3
3
# Integers
x = 5
y = -3
z = 0
print(type(x))
print(type(y))
print(type(z))
<class 'int'>
<class 'int'>
<class 'int'>
# 2. Floats
a = 3.14
b = -2.5
c = 0.0
print(type(a))
print(type(b))
print(type(c))
<class 'float'>
<class 'float'>
<class 'float'>
# 3. Strings
<class 'str'>
<class 'str'>
# Booleans
is_sunny = True
is_raining = False
print(type(is_sunny))
print(type(is_raining))
<class 'bool'>
<class 'bool'>
Variables
[Link] 2/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
1. Store Data: You can store values or results of computations in variables for later use.
2. Manipulate Data: You can perform operations or calculations using variables.
3. Reuse Data: Variables allow you to reuse the same value in multiple places within your code without having to repeat it.
print(dog)
doberman
# You create a variable by naming something, once you name it, you assign it a value,
# you assign the value after the equals (=) sign
# after the equals sign, you give your value
x = 5
y = "Hello, World!"
is_sunny = True
z = x * 2
greeting = y + " Welcome!"
print(z)
print(greeting)
10
Hello, World! Welcome!
# Modifying variables
x = x + 1
print(x)
x = 5
x_1 = "Hello"
print(x)
z = x + z
print(z)
15
Variable Names
1. Descriptive Names - Choose meaningful and descriptive names for variables to make your code easier to understand.
num_students = 20
2. Snake Case - Use snake_case (lowercase words separated by underscores) for variable names in Python.
total_amount = 100
3. Avoid Reserved Keywords - Avoid using Python reserved keywords (e.g., if, for, while) as variable names.
4. Dynamic Typing - Python is dynamically typed, meaning you don't need to declare the type of a variable explicitly. Python infers the
type based on the value assigned to it.
5. Constants - Although Python doesn't have built-in constants, programmers often use variables in all capital letters to represent
constants.
PI = 3.14
MAX_VALUE = 100
Variable Scope
1. Global Scope: Variables defined outside of any function or class are in the global scope and can be accessed from anywhere in the
code.
[Link] 3/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
2. Local Scope: Variables defined inside a function or a class method are in the local scope and can only be accessed within that
function or method.
# Global Scope
x = 10 # Global variable
def my_function():
print(x) # Accessing global variable from inside function
my_function()
10
def my_function_1():
y = 20 # Local variable
print(y)
my_function_1()
# print(y) # This will raise a NameError since y is not defined outside the function
20
Enclosing Scope (Nested Functions): Variables defined in an enclosing function are accessible within nested functions, but not outside
the enclosing function.
def outer_function():
z = 30
def inner_function():
print(z)
inner_function()
outer_function()
30
var_1 = 10
print(type(var_1))
<class 'int'>
Type conversion functions (int(), float(), str(), etc.) allow you to convert data from one type to another when needed.
var_1 = str(var_1)
print(type(var_1))
<class 'str'>
1053
<class 'str'>
a = '10'
b = '5'
c = '3'
print(type(a))
print(type(b))
print(type(c))
a_1 = int(a)
[Link] 4/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
b_1 = int(b)
c_1 = int(c)
print(type(a_1))
print(type(b_1))
print(type(c_1))
<class 'str'>
<class 'str'>
<class 'str'>
<class 'int'>
<class 'int'>
<class 'int'>
18
Arithmetic Operations
# Addition
result_addition = 5 + 3
print(result_addition)
# Addition of floats
result = 3.5 + 2.5
print(result)
6.0
# Mixed addition
result_1 = 4 + 2.5
print(result_1)
6.5
# Addition of variables
x = 10
y = 20
result_2 = x + y
print(result_2)
30
# Subtraction
result_subtraction = 5 - 3
print(result_subtraction)
# Addition
result_addition = 5 - 3
print(result_addition)
[Link] 5/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
# Subtraction of variables
x = 20
y = 10
result_4 = x - y
print(result_4)
10
"""# Removing elements from lists using the subtraction sigh, this will not work and will give you a 'TypeError'
numbers = [1, 2, 3, 4, 5]
numbers_removed = numbers - [3, 4]
print(numbers_removed)"""
'# Removing elements from lists using the subtraction sigh, this will not work and will give you a 'TypeError'\nnumbers = [1,
2, 3, 4, 5]\nnumbers_removed = numbers - [3, 4]\nprint(numbers_removed)'
# Multiplication (*)
result_multiplication = 4 * 6
print(result_multiplication)
24
# Multiplication
result_multiplication1 = -4 * 6
print(result_multiplication1)
-24
# Multiplication of variables
x = 10
y = 3
result_5 = x * y
print(result_5)
30
# Concatenating lists
numbers = [1, 2, 3]
numbers_multiplied = numbers * 2
print(numbers_multiplied)
[1, 2, 3, 1, 2, 3]
# Division of integers
result_6 = 10 / 3
print(result_6)
3.3333333333333335
# Division of variables
x = 20
y = 4
result_7 = x / y
print(result_7)
5.0
'# Division by zero - python does not support division by '0'\nresult_8 = 10 / 0\nprint(result_8)'
The floor division operator // is used to perform division and return the integer part of the result (rounded down).
[Link] 6/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
# Division of integers
result_9 = 10 // 3
print(result_9)
result_10 = 20 / 3
print(result_10)
6.666666666666667
result_11 = 20 // 3
print(result_11)
-4
# Modulus (Remainder)
result_modulus = 10 % 3
print(result_modulus)
# Modulus of floats
result_14 = 7.5 % 2.5
print(result_14)
0.0
The modulus operation in Python returns a result that has the same sign as the divisor (in this case, 3, which is positive).
However, since Python's modulus retains the divisor’s sign, it "wraps around" by adjusting the remainder to be non-negative. Instead of
returning -1, it returns 2 because 3 - 1 = 2.
True
Exponentiation (**)
[Link] 7/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
The exponentiation operator ** is used to raise one operand to the power of another.
# Exponentiation
result_exponentiation = 2 ** 3
print(result_exponentiation)
Combined arithmetic operations in Python follow the BODMAS (Brackets, Orders, Division and Multiplication, Addition and Subtraction)
rules, also known as the PEMDAS (Parentheses, Exponents, Multiplication and Division, Addition and Subtraction) rules.
Comparison Operations
Comparison operations in Python are used to compare values and determine the relationship between them.
These operations return a Boolean value (True or False) based on whether the comparison is true or false.
Python supports several comparison operators, which are commonly used to compare numbers, strings, and other data types.
# 1. Equal to (==) - The equal to operator == checks if two operands are equal.
# Equal to
result_16 = 5 == 5
print(result_16)
result_17 = 5 == 6
print(result_17)
True
False
x = 5
y = 5
result_18 = x == y # This will evaluate to True because x and y are equal.
print(result_18)
True
False
name1 = "Alice"
name2 = "Alice"
result_20 = name1 == name2
print(result_20)
[Link] 8/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
True
result_21 = (2 + 3) == (4 + 1)
print(result_21)
True
# 2. Not equal to (!=) - The not equal to operator != checks if two operands are not equal.
result_22 = 5 != 3
print(result_22)
True
result_23 = 3 != 3
print(result_23)
False
x = 5
y = 10
result_24 = x != y # This will evaluate to True because x and y are not equal.
print(result_24)
True
True
result_26 = (2 + 3) != (4 + 1)
print(result_26)
False
# 3. Greater than (>) - The greater than operator > checks if the left operand is greater than the right operand.
result_27 = 5 > 3
print(result_27)
True
result_28 = 2 > 3
print(result_28)
False
'''In Python, strings are compared lexicographically (based on the Unicode values of their characters).
In this example, "banana" is greater than "apple" because the Unicode value of 'b' is greater than 'a'.
'''
True
'In Python, strings are compared lexicographically (based on the Unicode values of their characters).\nIn this example, "banan
a" is greater than "apple" because the Unicode value of \'b\' is greater than \'a\'.\n'
age1 = 30
age2 = 25
result_30 = age1 > age2
print(result_30)
True
result_31 = (3 + 4) > (2 * 3)
print(result_31)
[Link] 9/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
True
# 4. Less than (<) - The less than operator < checks if the left operand is less than the right operand.
'''Assignment - try out the same codes we used for greater than but convert the symbol to less than instead'''
'Assignment - try out the same codes we used for greater than but convert the symbol to less than instead'
# 5. Greater than or equal to (>=) - The greater than or equal to operator >= checks if the left operand is greater than or eq
result_32 = 5 >= 5
print(result_32)
True
# 6. Less than or equal to (<=) - The less than or equal to operator <= checks if the left operand is less than or equal to th
result_33 = 5 <= 2
print(result_33)
False
Chaining comparison operators in Python allows you to compare multiple values in a single expression, making the code more concise and
readable. When you chain comparison operators, Python evaluates the expression from left to right and returns True only if all
comparisons in the chain are True.
# a < b < c
# a < b and b < c
x = 5
y = 10
z = 15
result_33 = x < y < z
print(result_33)
True
x = 5
y = 10
z = 2
result_34 = x < y < z
print(result_34)
False
Logical Operations
Logical operators are used to combine multiple conditions and return a boolean result.
keyboard_arrow_down AND
result_and = (5 > 3) and (7 < 10) # Output: True
OR
result_or = (4 == 4) or (6 != 6) # Output: True
NOT
result_not = not (3 > 5) # Output: True
[Link] 10/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
Logical operators in Python are used to combine conditional statements. These operators allow you to evaluate multiple conditions and
return a Boolean value (True or False) based on the logical relationships between them. The primary logical operators in Python are and,
or, and not.
and Operator
The and operator returns True if both operands are True. If either operand is False, it returns False. Syntax: condition1 and condition2
a = 5
b = 10
c = 15
result_35 = (a < b) and (b < c) # Both conditions are True, so result is True.
print(result_35)
True
a = 5
b = 10
c = 15
result_36 = (a < b) and (b > c) # Both conditions are not True, so result is True.
print(result_36)
False
is_raining = True
is_sunny = False
result_37 = is_raining and is_sunny # Both conditions need to be True.
print(result_37)
False
or Operator
The or operator returns True if at least one of the operands is True. If both operands are False, it returns False. Syntax: condition1 or
condition2
a = 5
b = 10
c = 15
True
a = 5
b = 10
c = 15
False
a = 5
b = 10
c = 15
result_40 = (a > b) or (b < c) or (a < c) # The second and third conditions are True.
print(result_40)
True
is_raining = True
is_sunny = False
[Link] 11/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
True
not Operator
The not operator is a unary operator that returns True if the operand is False, and False if the operand is True. Syntax: not condition
The not operator in Python is a logical operator used to invert the value of a boolean expression. It returns True if the operand is False, and
False if the operand is True. This operator is useful for reversing the meaning of a condition, making it the simplest form of logical
negation.
a = 5
b = 10
True
False
is_raining = True
result_44 = not is_raining # The variable is_raining is True, so not True is False.
print(result_44)
False
Python evaluates logical operators in the following order of precedence: not first, and second, or last. You can use parentheses to control
the order of evaluation explicitly.
a = 5
b = 10
c = 15
result_44 = not a < b and b < c # not (True) and True => False and True => False
# a < b = True; this would then mean that not True = False
# result_44 = False and b < c
# is b less than c = True
# result_44 = False and True
# when you are using the 'and' operator, you get back a 'True' output when all the consditions are 'True'
# In this instance, one of the conditions is False
# Which means, my overall output would then be False
print(result_44)
False
result_45 = not (a < b and b < c) # not (True and True) => not True => False
print(result_45)
False
Assignment Operations
y = 10
y += 3 # Equivalent to: y = y + 3 (adds 3 to the current value of y)
[Link] 12/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
Compound assignment operators combine a standard arithmetic or bitwise operation with assignment. They simplify the syntax and make
the code more concise.
Adds the right operand to the left operand and assigns the result to the left operand.
a = 5
a += 3 # Equivalent to a = a + 3
print(a)
Subtracts the right operand from the left operand and assigns the result to the left operand.
a = 5
a -= 2 # Equivalent to a = a - 2
print(a)
Multiplies the left operand by the right operand and assigns the result to the left operand.
a = 5
a *= 4 # Equivalent to a = a * 4
print(a)
20
Divides the left operand by the right operand and assigns the result to the left operand.
a = 10
a /= 2 # Equivalent to a = a / 2
print(a)
5.0
Performs floor division on the left operand by the right operand and assigns the result to the left operand.
a = 10
a //= 3 # Equivalent to a = a // 3
print(a)
[Link] 13/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
Takes the modulus using the left and right operands and assigns the result to the left operand.
a = 10
a %= 3 # Equivalent to a = a % 3
print(a)
Raises the left operand to the power of the right operand and assigns the result to the left operand.
a = 2
a **= 3 # Equivalent to a = a ** 3
print(a)
Membership Operations
Membership operators are used to test if a value is present in a sequence (e.g., list, tuple, string).
in Operator: Tests if a value exists in a sequence. Returns True if the value is found, otherwise returns False.
not in Operator: Tests if a value does not exist in a sequence. Returns True if the value is not found, otherwise returns False.
# 1. Using in Operator
True
False
True
True
False
# 2. not in Operator
False
True
Identity Operations
Identity operators are used to compare the memory locations of two objects.
These operators are essential for checking whether two variables point to the same object in memory. Python provides two identity
operators: is and is not.
x = [1, 2, 3]
y = [1, 2, 3]
# IS Operator
result_is = x is y
print(result_is)
False
[Link] 14/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
# IS NOT
result_is_not = x is not y
print(result_is_not)
True
is Operator: Tests if two variables refer to the same object. Returns True if both variables point to the same object, otherwise returns
False.
is not Operator: Tests if two variables do not refer to the same object. Returns True if both variables point to different objects, otherwise
returns False.
1. Lists
A list is an ordered, mutable collection of items. Lists can contain elements of different data types, including other lists.
Lists are one of the most versatile and commonly used data structures in Python. They allow you to store collections of items in a single
variable. Lists are ordered, mutable, and can contain elements of different data types, including other lists.
Creating a List A list is created by placing all the items (elements) inside square brackets [], separated by commas.
# Empty list
my_list = []
# List of integers
my_list = [1, 2, 3, 4, 5]
# List of lists
nested_list = [[1, 2, 3], ["a", "b", "c"]]
# List of integers
my_list = [1, 2, 3, 4, 5]
# python uses zero-based indexing - you start counting from zero (0)
# The number 1 in my_list occupies the position denoted by index 0, etc.
"""Ordered:
The elements in a list have a defined order. When you add items to a list, they are stored in a specific sequence. This order
"""
'Ordered:\nThe elements in a list have a defined order. When you add items to a list, they are stored in a specific sequence.
This order is maintained, which means the elements can be accessed and manipulated based on their position (index).\n'
"""Mutable:
Lists are mutable, meaning you can change their content after they are created. This includes adding, removing, and modifying
"""
'Mutable:\nLists are mutable, meaning you can change their content after they are created. This includes adding, removing, and
modifying elements \n'
"""Dynamic: Lists can grow and shrink in size as needed. You can add or remove elements dynamically.
"""
'Dynamic: Lists can grow and shrink in size as needed. You can add or remove elements dynamically.\n'
[Link] 15/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
print(fruits)
[Link]("banana")
print(fruits)
['apple', 'cherry']
# the code above removes a given item from your list by indicating the exact name of the item
'Indexing and Slicing:\nLists support indexing and slicing, allowing you to access and manipulate subparts of the list. Indexi
ng starts from 0 for the first element.\n'
print(fruits[2])
cherry
Accessing elements in lists is a fundamental operation that allows you to retrieve and manipulate data stored within the list.
Python provides several ways to access elements, including indexing, slicing, and using negative indices.
# 1. Basic Indexing: Elements in a list can be accessed by their index. Python uses zero-based indexing, which means the first
apple
banana
cherry
# Negative Indexing: Negative indexing allows you to access elements from the end of the list. The last element is at index -1
date
cherry
Slicing
[Link] 16/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
The syntax for slicing is list[start:end], where start is the index of the first element to include, and end is the index of the first element to
exclude.
# Basic Slicing
['banana', 'cherry']
List Methods
# extend(): Extends the list by appending elements from another list or any iterable.
['apple', 'cherry']
# pop(): Removes and returns the element at a specified position (default is the last element).
cherry
[]
[Link] 17/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
# sort(): Sorts the elements of the list in place (ascending order by default).
# You can also sort in descending order by passing the reverse=True argument.
[Link](reverse=True)
print(fruits)
# list() constructor: You can create a new list by passing an iterable to the list() constructor.
# len(): Although not a method of the list object, len() is a built-in function that returns the number of elements in a list
# where to get the comprehensive number of methods you can apply to 'lists' in python
[Link] 18/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
Tuples
A tuple is an ordered, immutable collection of items. Like lists, tuples can contain elements of different data types.
Tuples are one of the fundamental data structures in Python. They are similar to lists but have some distinct characteristics: their creation,
characteristics, and common operations.
# Creating Tuples
# 1. Creating an Empty Tuple - You can create an empty tuple using parentheses () or the tuple() function.
# Using parentheses
empty_tuple = ()
print(empty_tuple)
()
empty_tuple = tuple()
print(empty_tuple)
()
(1, 2, 3)
# 3. Creating a Tuple with One Element - To create a tuple with a single element, you must include a trailing comma. Without t
<class 'tuple'>
<class 'int'>
# 4. Creating a Tuple from an Iterable - You can create a tuple from any iterable (e.g., list, string, range) using the tuple
(1, 2, 3)
[Link] 19/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
print(my_tuple)
(0, 1, 2, 3, 4)
# 5. Creating Nested Tuples - Tuples can contain other tuples as elements, allowing you to create nested structures.
# 1. Ordered Collection - Tuples maintain the order of elements. This means that the order in which you insert elements into a
tuple_1 = (1, 2, 3, 4, 5)
print(tuple_1[0])
print(tuple_1[3])
1
4
'''# 2. Immutable - Once a tuple is created, its contents cannot be altered. This immutability makes tuples a reliable way to
tuple_2 = (1, 2, 3)
tuple_2[1] = 15'''
'# 2. Immutable - Once a tuple is created, its contents cannot be altered. This immutability makes tuples a reliable way to st
ore data that should not change throughout the program.\n\ntuple_2 = (1, 2, 3)\ntuple_2[1] = 15'
# 3. Heterogeneous - Tuples can contain elements of different data types, including integers, strings, lists, and even other t
# 4. Indexed - Tuples use zero-based indexing, allowing you to access elements directly by their index positions.
b
c
# 5. Hashable - Since tuples are immutable, they can be used as keys in dictionaries if all elements within the tuple are also
dictionary_1 = {(1, 2): "a pair of numbers", (3, 4): "another pair"}
print(dictionary_1[(1, 2)])
a pair of numbers
# 6. Built-in Methods - Tuples have a limited set of built-in methods, reflecting their immutability. The most common methods
tuple_5 = (1, 2, 3, 2, 2)
print(tuple_5.count(2))
tuple_6 = (1, 2, 3, 4)
print(tuple_6.index(3))
[Link] 20/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
# 1. Accessing Individual Elements - Accessing individual elements of a tuple in Python is straightforward and involves using
# 2. Negative Indexing - Negative indexing in Python allows you to access elements of a tuple starting from the end, rather th
print(my_tuple[-1])
a
3
# Unpacking a tuple - It allows you to work with the individual elements of a tuple without needing to index into it repeatedl
my_tuple_1 = (a, b, c)
a, b, c = my_tuple_1
print(a, b, c)
8 10 15
my_tuple_2 = (a, c, b)
p, q, r = my_tuple_2
print(p, q, r)
8 15 10
# Length - len() function - You can determine the number of elements in a tuple
# Syntax - len(tuple_name)
tuple1 = (1, 2, 3, 4)
# Finding the length of a tuple
len(tuple1)
# max() Function - The max() function takes a tuple as its argument and returns the maximum value present in the tuple.
tuple1 = (5, 1, 8, 3)
# Finding max value
print(max(tuple1))
apple
[Link] 21/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
# min() Function - The min() function takes a tuple as its argument and returns the minimum value present in the tuple.
tuple4 = (5, 1, 8, 3)
# Finding min value
print(min(tuple4))
'''# sum() - Description: Returns the sum of all elements in a tuple. - Syntax: sum(tuple_name)
tuple5 = (1, 2, 3)
print(sum(tuple5))
'''
'# sum() - Description: Returns the sum of all elements in a tuple. - Syntax: sum(tuple_name)\n\ntuple5 = (1, 2, 3)\nprint(sum
(tuple5))\n'
'''tuple6 = (2,3,4)
print(sum(tuple6))'''
'tuple6 = (2,3,4)\nprint(sum(tuple6))'
# sorted() - Description: Returns a sorted list of the tuple's elements. Syntax: sorted(tuple)
t = (3, 1, 2)
print(sorted(t))
print(tuple(sorted(t))) # the tuple function here converts the list output into a tuple
[1, 2, 3]
(1, 2, 3)
# all() - Description: Returns True if all elements in the tuple are true. - Syntax: all(tuple)
t = (1, 2, 3)
print(all(t))
True
t2 = (0, 1, 2)
print(all(t2))
False
True
# any() - Description: Returns True if any element in the tuple is true. - Syntax: any(tuple)
t1 = (1, 2, 3)
print(any(t1))
t3 = (0, 1, 2)
print(any(t3))
t4 = (0, 0, 2)
print(any(t4))
t5 = (0, 0, 0)
print(any(t5))
True
True
True
True
False
[Link] 22/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
To convert a list to a tuple, you can use the tuple() function. This is useful when you want to make a sequence immutable to prevent
accidental modifications.
my_list = [1, 2, 3, 4]
my_tuple = tuple(my_list)
print(my_tuple)
(1, 2, 3, 4)
To convert a tuple to a list, you can use the list() function. This is useful when you need to modify the contents of a sequence that was
initially a tuple.
my_tuple = (1, 2, 3, 4)
my_list = list(my_tuple)
print(my_list)
[1, 2, 3, 4]
# Nested structure
nested_tuple = ([1, 2, 3], [4, 5, 6])
Dictionaries
A dictionary is an unordered, mutable collection of key-value pairs. Each key must be unique and immutable, while values can be of any
data type.
Dictionaries are a powerful data structure in Python that allow you to store and manage data using key-value pairs. They are mutable,
unordered, and indexed by keys, which can be of any immutable type.
Key Features
1.** Key-Value Pairs** - Each element in a dictionary is a pair consisting of a key and a value.
To access the value associated with a specific key, you use the key in square brackets [].
[Link] 23/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
print(my_dict['age'])
print(my_dict['city'])
Alice
25
New York
my_dict = {'name': ['Alice', 'Brian', 'Lucy'], 'age': [25, 18, 32], 'city': ['New York', 'New York', 'Los Angeles']}
print(my_dict)
{'name': ['Alice', 'Brian', 'Lucy'], 'age': [25, 18, 32], 'city': ['New York', 'New York', 'Los Angeles']}
print(my_dict['name'][2])
Lucy
print(my_dict['city'][2])
Los Angeles
If you try to access a key that does not exist in the dictionary, Python will raise a KeyError.
To avoid this, you can use the .get() method which returns None (or a default value you provide) if the key is not found.
print (my_dict['name'])
Alice
'''print(my_dict['hobby'])'''
'print(my_dict['hobby'])'
print(my_dict.get('hobby'))
None
In Python, dictionaries are mutable, which means you can modify them after their creation. You can add new key-value pairs, update
existing ones, or remove them.
[Link] 24/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
"user1": {
"name": "Alice",
"age": 30,
"hobbies": ["Reading", "Hiking", "Coding"]
},
"user2": {
"name": "Bob",
"age": 25,
"hobbies": ["Gaming", "Traveling"]
},
"user3": {
"name": "Charlie",
"age": 35,
"hobbies": ["Swimming", "Cooking"]
}
}
print(data)
{'user1': {'name': 'Alice', 'age': 30, 'hobbies': ['Reading', 'Hiking', 'Coding']}, 'user2': {'name': 'Bob', 'age': 25, 'hobbie
user2_data = data["user2"]
print(user2_data)
25
26
print(data)
{'user1': {'name': 'Alice', 'age': 30, 'hobbies': ['Reading', 'Hiking', 'Coding']}, 'user2': {'name': 'Bob', 'age': 26, 'hobbie
Loop Control Statements Python provides several control statements to modify the behavior of loops, allowing for greater control over
how loops execute. These statements include break, continue, and else clauses with loops.
1. break Statement
The break statement is used to terminate the loop immediately, regardless of the loop's condition. Once the break statement is
encountered, the loop stops, and the execution continues with the statement immediately following the loop.
0
1
2
3
[Link] 25/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
4
2. continue Statement
The continue statement is used to skip the rest of the code inside the loop for the current iteration and proceed to the next iteration.
When continue is encountered, the loop's current iteration ends, and the next iteration begins.
1
3
5
7
9
The else block in a loop executes after the loop completes normally. If the loop is terminated by a break statement, the else block will not
be executed.
0
1
2
3
4
Loop completed
0
1
2
In Python, loops can be nested within other loops to perform more complex iterations. A nested loop is a loop inside another loop, where
the inner loop runs for each iteration of the outer loop.
for i in range(3):
for j in range(2):
print(f"i = {i}, j = {j}")
i = 0, j = 0
i = 0, j = 1
i = 1, j = 0
i = 1, j = 1
i = 2, j = 0
i = 2, j = 1
# 1. Multiplication Table
[Link] 26/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
1 * 1 = 1
1 * 2 = 2
1 * 3 = 3
----------
2 * 1 = 2
2 * 2 = 4
2 * 3 = 6
----------
3 * 1 = 3
3 * 2 = 6
3 * 3 = 9
----------
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
1 2 3
4 5 6
7 8 9
# 3. Pattern Generation
rows = 5
for i in range(1, rows + 1):
for j in range(1, i + 1):
print("*", end=" ")
print()
*
* *
* * *
* * * *
* * * * *
i = 0
while i < 3:
j = 0
while j < 2:
print(f"i = {i}, j = {j}")
j += 1
i += 1
i = 0, j = 0
i = 0, j = 1
i = 1, j = 0
i = 1, j = 1
i = 2, j = 0
i = 2, j = 1
for i in range(3):
j = 0
while j < 2:
print(f"i = {i}, j = {j}")
j += 1
i = 0, j = 0
i = 0, j = 1
i = 1, j = 0
i = 1, j = 1
i = 2, j = 0
i = 2, j = 1
[Link] 27/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
Functions
Functions are a fundamental aspect of programming in Python. They allow you to group code into reusable blocks, making your programs
easier to read, maintain, and debug. Functions encapsulate logic, making it possible to call the same block of code multiple times within a
progr
1. Defining a Function
In Python, functions are defined using the def keyword followed by the function name and parentheses (). A function can have
parameters, which are specified within the parentheses. These parameters act as placeholders for the values that will be passed to the
function when it is called. Functions allow you to encapsulate code into reusable blocks, making your programs more modular and easier
to manage.
def function_name(parameters):
# code to execute
return value
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
greet("Bob")
Hello, Alice!
Hello, Bob!
result = add(3, 5)
print(result)
print(add(4, 7))
8
11
result = product(3, 5)
print(result)
print(product(4, 7))
15
28
result = division(15, 3)
print(result)
print(division(36, 6))
5.0
6.0
In Python, parameters and arguments are fundamental concepts in the context of functions. Understanding the difference between them
and how they are used can help you write more effective and reusable code.
[Link] 28/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
Parameters
Parameters are the variables listed inside the parentheses in the function definition. They act as placeholders for the values that will be
passed to the function when it is called. Example def add(a, b): return a + b In this example, a and b are parameters of the function add.
Arguments
Arguments are the actual values passed to the function when it is called. These values are assigned to the corresponding parameters.
Example result = add(3, 5) print(result)
In this example, 3 and 5 are arguments passed to the add function. These values are assigned to the parameters a and b, respectively.
1. Positional Parameters
Positional parameters are the most common type. The arguments passed to the function are assigned to the parameters based on their
position.
greet("John", "Doe")
2. Default Parameters
You can provide default values for parameters. If no argument is passed, the default value is used.
def greet(name="World"):
print(f"Hello, {name}!")
greet()
greet("Alice")
Hello, World!
Hello, Alice!
3. Keyword Parameters
Keyword parameters allow you to specify arguments by parameter name, making function calls more readable.
describe_pet(animal_type="dog", pet_name="Buddy")
You can use *args to pass a variable number of positional arguments to a function.
del sum # This is to remove the user-defined sum variable we had used earlier in our code so that Python can access the built
def sum_all(*args):
return sum(args)
result = sum_all(1, 2, 3, 4)
print(result)
10
You can use **kwargs to pass a variable number of keyword arguments to a function.
[Link] 29/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
def describe_person(**kwargs):
for key, value in [Link]():
print(f"{key}: {value}")
name: Alice
age: 30
city: New York
Return Statement
Syntax
return is followed by the value or expression that you want to send back to the caller.
If a function does not have a return statement, it returns None by default.
def square(number):
return number ** 2
result = square(4)
print(result)
16
John Doe
John Doe
8
def evaluate_score(score):
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
elif score >= 60:
return "D"
else:
return "F"
grade = evaluate_score(85)
print(grade)
# You can use return to exit a function early, before the end of its code block.
[Link] 30/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
def find_first_even(numbers):
for number in numbers:
if number % 2 == 0:
return number
return None
None
Variable Scope
Variable scope refers to the visibility and accessibility of variables within different parts of a program.
In Python, understanding variable scope is crucial for writing clear, maintainable, and bug-free code.
Types of Scope
1. Local scope
2. Global scope
1. Local Scope
Local scope refers to the scope of variables that are declared inside a function.
These variables are only accessible within that function and not outside of it.
Access Restriction: These local variables cannot be accessed outside the function in which they are defined.
If you try to access a local variable from outside its function, you will encounter a NameError.
def my_function():
example = 10 # example is a local variable
print(example) # This will print 10
my_function()
10
def my_function():
example = 10 # example is a local variable
print(example) # This will print 10
my_function()
# print(example) # Uncommenting this line will raise a NameError because x is not defined outside my_function
10
Encapsulation: Local variables allow functions to be self-contained. This means that the internal workings of a function are hidden
from the rest of the program, promoting encapsulation.
Memory Management: Since local variables are destroyed after the function execution, it helps in efficient memory management.
Avoiding Naming Conflicts: Local variables enable the use of the same variable name in different functions without causing conflicts.
2. Global Scope
Global scope refers to variables that are defined outside of any function.
These variables are accessible from anywhere in the program, including inside functions.
x = 10 # x is a global variable
print(x) # This will also print 10, accessing the same global variable
10
x1 = 11
print(x1)
11
def my_function():
print(x) # This will print 10, accessing the global variable
[Link] 31/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
my_function()
10
Advantages
Convenience: Global variables can be convenient for values that need to be accessed by multiple functions throughout the program.
Sharing Data: Global variables can be used to share data between different parts of the program without the need to pass
parameters.
Disadvantages
Unintended Modifications: Since global variables can be accessed and modified from anywhere in the program, there is a risk of
unintended modifications that can lead to bugs.
Reduced Modularity: Relying heavily on global variables can make the program less modular and harder to maintain, as functions
become dependent on external state.
Namespace Pollution: Excessive use of global variables can lead to a cluttered global namespace, increasing the likelihood of
variable name conflicts.
Lambda Functions
Lambda functions, also known as anonymous functions, are a concise way to create functions without using the def keyword and defining
a formal function block.
They are especially useful for short, simple operations where defining a full-fledged function using def would be overkill.
Syntax
def square(x):
result = x ** 2
return result
print(square(3))
square = lambda x: x ** 2
print(square(3))
Lambda functions are often used in situations where you need a simple function for a short period of time.
They are commonly used with functions like map(), filter(), and sorted().
numbers = [1, 2, 3, 4, 5]
numbers_squared = list(map(lambda x: x ** 2, numbers))
print(numbers_squared)
[Link] 32/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
def multiply_by(n):
# Define an inner function using def instead of lambda
def multiplier(x):
return x * n
return multiplier
10
12
def multiply_by(n):
# This lambda returns another function that multiplies its input by 'n'
return lambda x: x * n
10
12
Single Expression: Lambda functions can only contain a single expression. They are not suitable for complex logic or multi-step
operations i.e. you can't create inner functions using lambda functions.
Limited Use Cases: While powerful, lambda functions are best suited for situations where the function is short-lived and used in a
specific context.
Class Exercise
Object-Oriented Programming (OOP) is a paradigm that revolves around the concept of objects, which are instances of classes.
In Python, OOP is a powerful way to structure and organize code, offering benefits such as modularity, reusability, and ease of
maintenance.
Importance of OOP
1. Understanding Libraries and Frameworks - Many popular libraries and frameworks used in data science, such as Pandas, NumPy,
Scikit-learn, and TensorFlow, are built using OOP principles. Understanding OOP helps students better grasp these tools and
libraries, enabling them to leverage their full capabilities.
2. Modular Code Design - OOP promotes modular code design, which is crucial for building complex data pipelines, machine learning
models, and data processing systems. It encourages encapsulation, abstraction, polymorphism, and inheritance, making code more
organized and maintainable.
3. Custom Classes and Data Structures - Data scientists often need to create custom classes and data structures to represent specific
data entities or models. For example, a class to encapsulate a machine learning model with training, prediction, and evaluation
methods. OOP provides a structured approach to designing and implementing such classes.
4. Collaboration with Software Engineers - Data scientists often collaborate with software engineers and developers in building
production-grade systems. Knowledge of OOP facilitates effective communication and collaboration with engineering teams,
ensuring seamless integration of data science solutions into larger software projects.
5. Career Flexibility and Versatility - Data scientists who are proficient in OOP are better positioned to transition into roles that require
software development skills or move into more technical leadership roles within data science teams. It broadens their career
[Link] 33/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
opportunities beyond traditional data analysis and modeling.
1. Class
Syntax
class ClassName: def init(self, param1, param2, ...): self.attribute1 = param1 self.attribute2 = param2 # More attributes
def method1(self):
# Method implementation
pass
def method2(self):
# Method implementation
pass
self.attribute1 = param1: Defines an instance attribute attribute1 and initializes it with param1.
self.attribute2 = param2: Defines another instance attribute attribute2 and initializes it with param2.
Methods (def method1(self):, def method2(self):): Functions defined inside the class that define the behavior of the class's objects.
These methods can access and manipulate the object's attributes using the self parameter.
class Car:
def __init__(self, brand, model):
[Link] = brand
[Link] = model
def display_info(self):
print(f"Car: {[Link]} {[Link]}")
# Usage
my_car = Car("Toyota", "Camry")
my_car.display_info()
1. Abstraction
Abstraction is a fundamental principle of Object-Oriented Programming (OOP) that simplifies complex systems by hiding the underlying
implementation details and exposing only the necessary features to the user. This allows developers to work with higher-level concepts
without needing to understand the intricate workings of these concepts.
Definition
Abstraction involves hiding the complex implementation details and exposing only the essential features of an object. It allows developers
to focus on what an object does rather than how it does it.
In Python, abstraction can be achieved through the use of abstract classes and methods. The abc (Abstract Base Classes) module in
Python provides the infrastructure for defining abstract base classes.
An abstract class can contain one or more abstract methods. An abstract method is a method that is declared but contains no
implementation. Concrete subclasses of the abstract class are required to implement these abstract methods.
[Link] 34/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def sound(self):
pass
class Dog(Animal):
def sound(self):
return "Bark"
class Cat(Animal):
def sound(self):
return "Meow"
class Lion(Animal):
def sound(self):
return 'Roar'
dog = Dog()
cat = Cat()
lion = Lion()
print([Link]())
print([Link]())
print([Link]())
Bark
Meow
Roar
Animal is an abstract class that inherits from ABC (Abstract Base Class). It has an abstract method sound decorated with
@abstractmethod. This method does not have any implementation.
Dog and Cat are concrete classes that inherit from the Animal abstract class. Both classes provide their own implementation of the sound
method.
An abstract class cannot be instantiated directly. Attempting to create an instance of Animal will result in an error.
Instances of the Dog and Cat classes can be created, and their sound methods can be called to return "Bark" and "Meow" respectively.
Benefits of Abstraction
Focus on What an Object Does - By hiding the implementation details, abstraction allows developers to focus on what an object does
rather than how it does it. This simplifies the development process.
Promotes Reusability - Abstract classes can define a template for a group of related classes. This promotes code reuse by providing a
common interface for different implementations.
Improves Code Maintainability - By separating the interface from the implementation, abstraction makes it easier to modify or extend the
code. Changes to the implementation do not affect the code that relies on the abstract interface.
Encourages Modular Design - Abstraction helps in designing modular systems where different components interact through well-defined
interfaces. This modularity enhances the maintainability and scalability of the system.
Software Libraries - Abstract classes and methods are commonly used in software libraries to define common interfaces. Users of the
library interact with these interfaces without needing to know the underlying implementation.
Frameworks - Frameworks often use abstraction to define the basic structure and behavior of applications. Developers extend abstract
classes to create specific functionality.
Plugins and Extensions - Abstraction is used to define plugin interfaces. Plugins implement these interfaces to extend the functionality of
an application.
2. Encapsulation
[Link] 35/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
class Car:
def __init__(self, model, year):
[Link] = model
self.__year = year # Private attribute
def display_info(self):
return f"Model: {[Link]}, Year: {self.__year}"
car.set_year(1990)
print(car.display_info())
Class Definition
The Car class is defined with two attributes: model and __year. The __year attribute is private, indicated by the double underscore prefix.
Constructor Method
The init method initializes the model and __year attributes when a new instance of the Car class is created.
The display_info method returns a string that includes the model and year of the car. This method provides controlled access to the
private __year attribute.
The set_year method allows for setting the year of the car, but only if the year is greater than 1885. This method ensures that the __year
attribute is updated in a controlled manner.
Direct access to the private __year attribute from outside the class is not allowed. Attempting to do so will raise an AttributeError.
The private attribute can only be accessed through the public methods display_info and set_year.
Benefits of Encapsulation
1. Data Protection - Encapsulation protects an object's internal state from unintended or harmful interference by restricting direct
access to its attributes. This ensures that the object’s data is always in a valid state.
2. Controlled Access - By providing getter and setter methods (accessors and mutators), encapsulation allows controlled access to an
object's [Link] ensures that any changes to the attributes follow the rules defined within these methods.
3. Modularity - Encapsulation helps in creating modular code where each class is responsible for its own data and behavior. This
modularity makes the code easier to understand, maintain, and extend.
4. Improved Debugging - With encapsulation, you can add logging or validation logic within the setter methods to track changes and
identify bugs more easily.
1. Data Validation - Encapsulation is commonly used to validate data before it is set on an object. This ensures that the object’s state
remains consistent and valid.
2. Security - Encapsulation provides a layer of security by hiding sensitive data from external access. Only trusted methods within the
class can access and modify this data.
3. API Design - When designing APIs, encapsulation helps in exposing only the necessary parts of an object, hiding the implementation
details. This makes the API easier to use and reduces the risk of misuse.
[Link] 36/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
**3. Inheritance **
Inheritance allows a class (subclass/derived class) to inherit attributes and methods from another class (superclass/base class).
# Superclass Definition - Vehicle is the superclass with two attributes: brand and model. It includes a method display_info tha
class Vehicle:
def __init__(self, brand, model):
[Link] = brand
[Link] = model
def display_info(self):
return f"Brand: {[Link]}, Model: {[Link]}"
# Subclass Definition - Car is the subclass that inherits from the Vehicle class. It has an additional attribute year and a mod
class Car(Vehicle):
def __init__(self, brand, model, year):
super().__init__(brand, model)
[Link] = year
def display_info(self):
return f"Brand: {[Link]}, Model: {[Link]}, Year: {[Link]}"
class Truck(Vehicle):
def __init__(self, brand, model, weight_capacity):
super().__init__(brand, model)
self.weight_capacity = weight_capacity
def display_info(self):
return f"Brand: {[Link]}, Model: {[Link]}, Weight_Capacity: {self.weight_capacity}"
Benefits of Inheritance
1. Code Reuse - Inheritance promotes code reuse by allowing a subclass to inherit and use the attributes and methods of its
superclass. This reduces code duplication.
2. Hierarchical Classification - Inheritance supports the organization of classes in a hierarchical manner. This makes it easier to
understand and manage complex systems.
3. Extensibility - Subclasses can extend or modify the behavior of the superclass by adding new attributes and methods or by
overriding existing ones.
4. Maintainability - Changes made to the superclass are automatically inherited by the subclasses. This centralizes common behavior,
making the code easier to maintain.
Software Libraries - Inheritance is commonly used in software libraries to create a base class with common functionality that can be
extended by other classes.
Frameworks - Frameworks use inheritance to provide a base class that developers can extend to create specific functionality for
their applications.
User Interface Components - Inheritance is often used to create a base class for UI components with common behavior, which can
be extended to create specific types of components.
Domain Models - In domain modeling, inheritance helps in representing real-world hierarchies and relationships between entities.
# Multiple Inheritance
class Flyable:
def fly(self):
return "Flying"
class Swimmable:
def swim(self):
return "Swimming"
[Link] 37/38
9/9/25, 8:14 PM Python_Programming.ipynb - Colab
class Duck(Flyable, Swimmable):
pass
duck = Duck()
print([Link]())
print([Link]())
Flying
Swimming
class Eagle(Flyable):
pass
eagle = Eagle()
print([Link]())
Flying
4. Polymorphism
Polymorphism refers to the ability of different classes to be treated as instances of the same class through a common interface.
It allows methods to be called on objects of different classes and have them behave differently based on their own implementation.
class Bird:
def fly(self):
return "Bird is flying"
class Airplane:
def fly(self):
return "Airplane is flying"
class Kite:
def fly(self):
return "Kite is flying"
# Polymorphic function
def let_it_fly(flying_object):
print(flying_object.fly())
bird = Bird()
airplane = Airplane()
kite = Kite()
let_it_fly(bird)
let_it_fly(airplane)
let_it_fly(kite)
Bird is flying
Airplane is flying
Kite is flying
Benefits of Polymorphism
1. Code Flexibility - Polymorphism increases flexibility in the code by allowing a single function to operate on objects of different
classes.
2. Ease of Maintenance - Polymorphic behavior makes the code easier to maintain and extend, as new classes with common interfaces
can be added without modifying existing functions.
3. Enhanced Readability - Using polymorphism, code readability is improved as the same operation can be applied to different objects
in a straightforward manner.
4. Dynamic Behavior - Polymorphism enables dynamic behavior where the appropriate method is called based on the object's class at
runtime, rather than compile-time.
[Link] 38/38