TAP AcademyTAP Academy

Python · NumPy · pandas

Output and variables

print()

Shows something on the screen. Anything in quotes is text; anything without is worked out first.

Code
print("Hello, Data Analytics")
print(2026)
print(60 * 7)
Output
Hello, Data Analytics 2026 420

Printing multiple values

Separate the parts with commas. Python puts a single space between them for you.

Code
name = "Rahul"
dept = "HR"
print("Employee", name, "works in", dept)
Output
Employee Rahul works in HR

Comments

Anything after a # is ignored by Python. It is a note for the human reading the code.

Code
# this line does nothing at all
salary = 47764      # monthly, in rupees
print(salary)
Output
47764

Variables

A name that holds a value. Assign with a single =, and you can change it later.

Code
emp_id = 1001
name   = "Rahul Sharma"
salary = 47764

print(emp_id, name, salary)

salary = 52000          # changed
print("after the hike:", salary)
Output
1001 Rahul Sharma 47764 after the hike: 52000
Practice — Output and variables
1. Store your own name, your city and your age in three variables, then print them in one sentence.
Show one way to do it
name = "Anita"
city = "Chennai"
age  = 22
print(name, "is", age, "and lives in", city)
Output
Anita is 22 and lives in Chennai

Data types

int

Counting numbers, positive or negative, with no decimal point.

Code
experience = 4
print(experience)
print(type(experience))
Output
4 <class 'int'>

float

Any number with a dot in it. Division always produces one, even when it divides evenly.

Code
height = 169.5
print(height, type(height))
print(10 / 2, type(10 / 2))
Output
169.5 <class 'float'> 5.0 <class 'float'>

str

Anything inside quotes. Single or double quotes both work, as long as you match them.

Code
dept = 'HR'
city = "Hyderabad"
print(dept, city)
print(type(dept))
Output
HR Hyderabad <class 'str'>

bool

Only two possible values, and both start with a capital letter.

Code
is_active = True
print(is_active, type(is_active))
print(5 > 3)
print(5 == 3)
Output
True <class 'bool'> True False

type()

Asks Python what something is. Useful the moment a value does not behave the way you expected.

Code
print(type(10))
print(type(10.0))
print(type("10"))
print(type(True))
Output
<class 'int'> <class 'float'> <class 'str'> <class 'bool'>
Practice — Data types
1. Print the type of each of these: 7, 7.0, "7", True. Say out loud why 7 and "7" are different.
Show one way to do it
for v in [7, 7.0, "7", True]:
    print(v, "->", type(v))
Output
7 -> <class 'int'> 7.0 -> <class 'float'> 7 -> <class 'str'> True -> <class 'bool'>

Type conversion

int()

Turns something into a whole number. On a float it CUTS the decimal off — it does not round.

Code
print(int("25"))
print(int(9.99))        # 9, not 10
print(int(True))
Output
25 9 1

float() and str()

float() adds a decimal point, str() turns a number into text so it can be joined to other text.

Code
print(float(25), type(float(25)))
print(str(25) + " employees")
Output
25.0 <class 'float'> 25 employees

Text and numbers behave differently

"25" and 25 look the same on screen and behave completely differently. Text repeats; numbers add.

Code
print("25" + "25")      # text joins
print(25 + 25)          # numbers add
print(int("25") + 25)   # convert first
Output
2525 50 50

Invalid conversion

int() only works on something that really is a number. Anything else stops the program.

Code
print(int("50"))
print(int("fifty"))
Output
50 ValueError: invalid literal for int() with base 10: 'fifty'
Practice — Type conversion
1. A salary arrives as the text "47764". Add a 10% bonus to it and print the total.
Show one way to do it
salary = "47764"
total = int(salary) + int(salary) * 10 / 100
print(total)
Output
52540.4

Input

input()

Stops and waits for the user to type. Whatever they type arrives as TEXT, always.

Code
name = input("Enter your name: ")
print("Welcome,", name)
print(type(name))
Output
Enter your name: Priya Welcome, Priya <class 'str'>

input() returns text

input() hands back text, so you must convert before doing any maths with it.

Code
age = input("Enter your age: ")
print("next year you are", age + 1)
Output
Enter your age: 23 TypeError: can only concatenate str (not "int") to str

Converting input

Wrap input() in int() — or float() if decimals are possible.

Code
age = int(input("Enter your age: "))
print("next year you are", age + 1)
Output
Enter your age: 23 next year you are 24
Practice — Input
1. Ask for two numbers and print their sum. Make sure it adds rather than joins.
Show one way to do it
a = int(input("first number: "))
b = int(input("second number: "))
print("sum is", a + b)
Output
first number: 12 second number: 30 sum is 42

Operators

Arithmetic

The usual five, plus // for whole-number division and % for the remainder.

Code
a, b = 17, 5
print("add      ", a + b)
print("subtract ", a - b)
print("multiply ", a * b)
print("divide   ", a / b)      # always a float
print("floor    ", a // b)     # whole part only
print("remainder", a % b)
print("power    ", a ** 2)
Output
add 22 subtract 12 multiply 85 divide 3.4 floor 3 remainder 2 power 289

Modulo

The remainder operator is how you check whether a number divides evenly. Remainder 0 means it does.

Code
for n in [10, 7, 24]:
    if n % 2 == 0:
        print(n, "is even")
    else:
        print(n, "is odd")
Output
10 is even 7 is odd 24 is even

Comparison

Six of them, and every one hands back True or False. Note == is a question, = is an instruction.

Code
salary = 47764
print(salary > 50000)
print(salary < 50000)
print(salary == 47764)
print(salary != 47764)
print(salary >= 47764)
Output
False True True False True

Logical operators

Join two conditions. and needs both true; or needs one; not flips it.

Code
dept, salary = "Tech", 62990

print(dept == "Tech" and salary > 50000)
print(dept == "HR"   or  salary > 50000)
print(not dept == "Tech")
Output
True True False
Practice — Operators
1. Ask for a number and say whether it is even or odd.
Show one way to do it
n = int(input("number: "))
if n % 2 == 0:
    print(n, "is even")
else:
    print(n, "is odd")
Output
number: 18 18 is even
2. An employee is in Tech AND earns over 50,000. Print True or False for salary 48,000.
Show one way to do it
dept, salary = "Tech", 48000
print(dept == "Tech" and salary > 50000)
Output
False

Conditional statements

if

Runs the indented block only when the condition is True. The colon and the indent are both required.

Code
salary = 62990

if salary > 50000:
    print("above fifty thousand")

print("this line always runs")
Output
above fifty thousand this line always runs

if and else

Two paths, and exactly one of them runs.

Code
age = 17

if age >= 18:
    print("can vote")
else:
    print("cannot vote yet")
Output
cannot vote yet

if, elif and else

More than two paths. Python checks top to bottom and stops at the FIRST one that is true.

Code
marks = 72

if marks >= 90:
    print("A")
elif marks >= 75:
    print("B")
elif marks >= 60:
    print("C")
else:
    print("D")
Output
C

Condition order

Because it stops at the first match, a loose condition placed first swallows all the rest.

Code
marks = 95

# WRONG - 95 is >= 60, so it stops here
if marks >= 60:
    print("C")
elif marks >= 90:
    print("A")      # never reached
Output
C

Nested if

An if inside another if. The inner one is only reached when the outer one passed.

Code
dept, salary = "Tech", 62990

if dept == "Tech":
    if salary > 50000:
        print("senior tech")
    else:
        print("junior tech")
else:
    print("not tech")
Output
senior tech
Practice — Conditional statements
1. Grade a mark out of 100: 90+ A, 75+ B, 60+ C, 40+ D, below that Fail. Test it with 61.
Show one way to do it
marks = 61
if marks >= 90:
    print("A")
elif marks >= 75:
    print("B")
elif marks >= 60:
    print("C")
elif marks >= 40:
    print("D")
else:
    print("Fail")
Output
C
2. Ask for a year and print whether it is a leap year. (Divisible by 4, but not by 100, unless also by 400.)
Show one way to do it
y = int(input("year: "))
if y % 400 == 0:
    print(y, "is a leap year")
elif y % 100 == 0:
    print(y, "is not a leap year")
elif y % 4 == 0:
    print(y, "is a leap year")
else:
    print(y, "is not a leap year")
Output
year: 2024 2024 is a leap year

Loops

for

Walks through a collection one item at a time. The variable after for is a name you choose.

Code
depts = ["HR", "Tech", "Sales", "Marketing"]

for d in depts:
    print(d)
Output
HR Tech Sales Marketing

range()

Produces a run of numbers. The stop value is NEVER included — range(5) gives 0 to 4.

Code
for i in range(5):
    print(i, end=" ")
print()

for i in range(1, 6):
    print(i, end=" ")
print()

for i in range(0, 20, 5):      # start, stop, step
    print(i, end=" ")
Output
0 1 2 3 4 1 2 3 4 5 0 5 10 15

for with range(len())

range(len(...)) gives you the positions, which you need when you want the position as well as the value.

Code
depts = ["HR", "Tech", "Sales"]

for i in range(len(depts)):
    print(i, depts[i])
Output
0 HR 1 Tech 2 Sales

while

Repeats while a condition stays True. YOU have to change something inside, or it never stops.

Code
count = 1
while count <= 5:
    print(count, end=" ")
    count = count + 1
Output
1 2 3 4 5

break

Leaves the loop immediately, no matter how many items are left.

Code
for n in [12, 7, 40, 3, 55]:
    if n > 30:
        print("found one over 30:", n)
        break
    print("checked", n)
Output
checked 12 checked 7 found one over 30: 40

continue

Skips the rest of THIS turn and jumps to the next one. The loop keeps going.

Code
for n in range(1, 11):
    if n % 2 != 0:
        continue          # skip the odd ones
    print(n, end=" ")
Output
2 4 6 8 10

Nested loops

A loop inside a loop. The inner one runs completely for every single turn of the outer one.

Code
for i in range(1, 4):
    for j in range(1, 4):
        print(i * j, end="\t")
    print()
Output
1 2 3 2 4 6 3 6 9
Practice — Loops
1. Print the 7 times table from 7x1 to 7x10, one line each.
Show one way to do it
for i in range(1, 11):
    print("7 x", i, "=", 7 * i)
Output
7 x 1 = 7 7 x 2 = 14 7 x 3 = 21 7 x 4 = 28 7 x 5 = 35 7 x 6 = 42 7 x 7 = 49 7 x 8 = 56 7 x 9 = 63 7 x 10 = 70
2. Add up every number from 1 to 100 using a loop. (The answer is 5050.)
Show one way to do it
total = 0
for n in range(1, 101):
    total = total + n
print(total)
Output
5050
3. Print the numbers 1 to 20, but skip every multiple of 3.
Show one way to do it
for n in range(1, 21):
    if n % 3 == 0:
        continue
    print(n, end=" ")
Output
1 2 4 5 7 8 10 11 13 14 16 17 19 20
4. Count down from 10 to 1 using a while loop, then print 'Go'.
Show one way to do it
n = 10
while n >= 1:
    print(n, end=" ")
    n = n - 1
print("Go")
Output
10 9 8 7 6 5 4 3 2 1 Go

Lists

Creating and indexing

Ordered, changeable, and allows duplicates. Counting starts at 0; -1 is the last one.

Code
marks = [45, 72, 88, 61, 95]

print(marks)
print(marks[0])
print(marks[-1])
print(len(marks))
Output
[45, 72, 88, 61, 95] 45 95 5

Slicing

Take a range of items. The stop is not included, so [1:4] gives positions 1, 2 and 3.

Code
marks = [45, 72, 88, 61, 95]

print(marks[1:4])
print(marks[:3])
print(marks[2:])
print(marks[-2:])
print(marks[::2])
print(marks[::-1])     # reversed
Output
[72, 88, 61] [45, 72, 88] [88, 61, 95] [61, 95] [45, 88, 95] [95, 61, 88, 72, 45]

Modifying a list

Unlike a string, a list can be edited in place.

Code
marks = [45, 72, 88]
marks[0] = 50
print(marks)
Output
[50, 72, 88]

append / insert / extend

append adds one to the end, insert puts one at a position, extend adds a whole list.

Code
m = [45, 72]
m.append(88)
print(m)
m.insert(1, 60)
print(m)
m.extend([91, 33])
print(m)
Output
[45, 72, 88] [45, 60, 72, 88] [45, 60, 72, 88, 91, 33]

remove / pop / clear

remove deletes by VALUE, pop deletes by POSITION and hands it back, clear empties the list.

Code
m = [45, 72, 88, 61]
m.remove(72)
print(m)
taken = m.pop(0)
print("popped", taken, "->", m)
print(m.pop())      # no number = the last one
Output
[45, 88, 61] popped 45 -> [88, 61] 61

sort / reverse / count / index

sort changes the list itself. sorted() leaves it alone and hands back a new one.

Code
m = [45, 72, 88, 61, 72]
m.sort()
print(m)
m.sort(reverse=True)
print(m)
print("how many 72s:", m.count(72))
print("where is 88:", m.index(88))
Output
[45, 61, 72, 72, 88] [88, 72, 72, 61, 45] how many 72s: 2 where is 88: 0

sum, max and min

Totals and extremes.

Code
marks = [45, 72, 88, 61, 95]
print("total  ", sum(marks))
print("highest", max(marks))
print("lowest ", min(marks))
print("average", sum(marks) / len(marks))
Output
total 361 highest 95 lowest 45 average 72.2
Practice — Lists
1. From [45, 72, 88, 61, 95], print the highest, the lowest and the average.
Show one way to do it
m = [45, 72, 88, 61, 95]
print("highest", max(m))
print("lowest ", min(m))
print("average", sum(m) / len(m))
Output
highest 95 lowest 45 average 72.2
2. Given a list of marks, print only the ones above the average.
Show one way to do it
m = [45, 72, 88, 61, 95]
avg = sum(m) / len(m)
print("average is", avg)
for x in m:
    if x > avg:
        print(x, "is above")
Output
average is 72.2 88 is above 95 is above
3. Reverse a list without using reverse() or [::-1].
Show one way to do it
m = [45, 72, 88, 61]
out = []
for i in range(len(m) - 1, -1, -1):
    out.append(m[i])
print(out)
Output
[61, 88, 72, 45]

Tuples

Creating a tuple

Round brackets instead of square. Everything about reading it is the same; writing is forbidden.

Code
point = (10, 20, 30)
print(point)
print(point[0])
print(point[1:])
print(len(point))
Output
(10, 20, 30) 10 (20, 30) 3

Tuples cannot be changed

A tuple does not support item assignment.

Code
point = (10, 20, 30)
point[0] = 99
Output
TypeError: 'tuple' object does not support item assignment

Tuple methods

When the values must not be edited by accident — fixed settings, coordinates, a database row.

Code
WEEKDAYS = ("Mon", "Tue", "Wed", "Thu", "Fri")
print(len(WEEKDAYS), "working days")
print("Wed" in WEEKDAYS)
print(WEEKDAYS.count("Mon"), WEEKDAYS.index("Thu"))
Output
5 working days True 1 3
Practice — Tuples
1. Make a tuple of the five weekdays, print how many there are, and check whether 'Sun' is in it.
Show one way to do it
days = ("Mon", "Tue", "Wed", "Thu", "Fri")
print(len(days))
print("Sun" in days)
Output
5 False

Sets

Creating a set

Curly brackets. No duplicates, and NO ORDER — so you cannot ask for set[0], and printing one gives the items in whatever order Python feels like. Wrap it in sorted() when you need a fixed order.

Code
depts = {"HR", "Tech", "HR", "Sales", "Tech"}

print(len(depts))          # the 2 repeats are gone
print(sorted(depts))      # sorted, so it looks the same every run
print("HR" in depts)
Output
3 ['HR', 'Sales', 'Tech'] True

Removing duplicates from a list

Wrapping a list in set() gives its distinct values.

Code
entries = ["HR", "Tech", "HR", "Sales", "Tech", "HR"]

print(sorted(set(entries)))
print("distinct departments:", len(set(entries)))
Output
['HR', 'Sales', 'Tech'] distinct departments: 3

add, remove and discard

remove complains if the item is not there. discard does not.

Code
s = {"HR", "Tech"}
s.add("Sales")
print(s == {"HR", "Tech", "Sales"})
s.discard("Finance")     # not there, no error
s.remove("HR")
print(sorted(s))
Output
True ['Sales', 'Tech']

union, intersection and difference

The school set theory, as code. Useful for comparing two groups of anything.

Code
a = {"Rahul", "Priya", "Amit"}
b = {"Priya", "Amit", "Kavya"}

print(sorted(a | b))     # in either
print(sorted(a & b))     # in both
print(sorted(a - b))     # only in a
Output
['Amit', 'Kavya', 'Priya', 'Rahul'] ['Amit', 'Priya'] ['Rahul']
Practice — Sets
1. From ['HR','Tech','HR','Sales','Tech','HR'], print the distinct departments and how many there are.
Show one way to do it
e = ["HR", "Tech", "HR", "Sales", "Tech", "HR"]
d = set(e)
print(sorted(d))
print(len(d), "distinct")
Output
['HR', 'Sales', 'Tech'] 3 distinct
2. Two teams are given as sets. Print who is on both teams, and who is only on the first.
Show one way to do it
a = {"Rahul", "Priya", "Amit"}
b = {"Priya", "Amit", "Kavya"}
print("both:", sorted(a & b))
print("only a:", sorted(a - b))
Output
both: ['Amit', 'Priya'] only a: ['Rahul']

Dictionaries

Creating a dictionary

Instead of a position you use a name. That name is the key, and it has to be unique.

Code
emp = {"name": "Rahul", "dept": "HR", "salary": 47764}

print(emp)
print(emp["name"])
print(len(emp))
Output
{'name': 'Rahul', 'dept': 'HR', 'salary': 47764} Rahul 3

get()

Square brackets raise an error if the key is missing. get() hands back None, or whatever you choose.

Code
emp = {"name": "Rahul", "dept": "HR"}

print(emp.get("dept"))
print(emp.get("city"))                 # None, not an error
print(emp.get("city", "not recorded"))
Output
HR None not recorded

Adding and changing entries

Assign to a key that exists and it updates. Assign to a new one and it is added.

Code
emp = {"name": "Rahul", "dept": "HR"}
emp["salary"] = 47764      # new
emp["dept"]   = "Tech"     # changed
print(emp)
del emp["dept"]
print(emp)
Output
{'name': 'Rahul', 'dept': 'Tech', 'salary': 47764} {'name': 'Rahul', 'salary': 47764}

keys, values and items

items() is used when both the key and the value are needed.

Code
emp = {"name": "Rahul", "dept": "HR", "salary": 47764}

print(list(emp.keys()))
print(list(emp.values()))

for k, v in emp.items():
    print(k, "->", v)
Output
['name', 'dept', 'salary'] ['Rahul', 'HR', 47764] name -> Rahul dept -> HR salary -> 47764

Counting with a dictionary

A dictionary of counts, built in one pass over the data.

Code
depts = ["HR", "Tech", "HR", "Sales", "Tech", "HR"]

counts = {}
for d in depts:
    counts[d] = counts.get(d, 0) + 1

print(counts)
Output
{'HR': 3, 'Tech': 2, 'Sales': 1}
Practice — Dictionaries
1. Build a dictionary for one employee with name, department and salary, then print each key and value on its own line.
Show one way to do it
emp = {"name": "Priya", "dept": "Tech", "salary": 62990}
for k, v in emp.items():
    print(k, "->", v)
Output
name -> Priya dept -> Tech salary -> 62990
2. Count how many times each letter appears in the word 'statistics'.
Show one way to do it
word = "statistics"
counts = {}
for ch in word:
    counts[ch] = counts.get(ch, 0) + 1
print(counts)
Output
{'s': 3, 't': 3, 'a': 1, 'i': 2, 'c': 1}

Defining functions

def

A block of code with a name, written once and used as many times as you like. Note the colon and the indent.

Code
def greet():
    print("Welcome to Data Analytics")

greet()
greet()
Output
Welcome to Data Analytics Welcome to Data Analytics

Parameters and arguments

The name in the brackets is a parameter. The value you send is the argument.

Code
def greet(name):
    print("Welcome,", name)

greet("Rahul")
greet("Priya")
Output
Welcome, Rahul Welcome, Priya

return

Hands a value BACK so it can be stored or used. A function with no return hands back None.

Code
def add(a, b):
    return a + b

total = add(10, 20)
print(total)
print(add(5, 6) * 2)
Output
30 22

print and return

print shows something; return gives it back to the code.

Code
def shows(a, b):
    print(a + b)

def gives(a, b):
    return a + b

x = shows(2, 3)
y = gives(2, 3)
print("x is", x)      # None - nothing came back
print("y is", y)
Output
5 x is None y is 5

Returning multiple values

Separate them with commas and they come back as a tuple, which you can unpack straight away.

Code
def stats(nums):
    return min(nums), max(nums), sum(nums) / len(nums)

lo, hi, avg = stats([45, 72, 88, 61])
print(lo, hi, avg)
Output
45 88 66.5
Practice — Defining functions
1. Write a function that takes a list of marks and returns the average.
Show one way to do it
def average(marks):
    return sum(marks) / len(marks)

print(average([45, 72, 88, 61]))
Output
66.5
2. Write a function is_even(n) that RETURNS True or False, then use it in a loop over 1 to 6.
Show one way to do it
def is_even(n):
    return n % 2 == 0

for n in range(1, 7):
    print(n, is_even(n))
Output
1 False 2 True 3 False 4 True 5 False 6 True
3. Write a function that takes a salary and returns it with a 10% hike applied.
Show one way to do it
def hike(salary, pct=10):
    return salary + salary * pct / 100

print(hike(47764))
print(hike(47764, 20))
Output
52540.4 57316.8

Function arguments

Positional arguments

Matched by ORDER. Swap them round and you quietly get the wrong answer, with no error.

Code
def detail(name, dept):
    print(name, "works in", dept)

detail("Rahul", "HR")
detail("HR", "Rahul")      # no error - just wrong
Output
Rahul works in HR HR works in Rahul

Keyword arguments

Matched by NAME, so the order stops mattering.

Code
def detail(name, dept):
    print(name, "works in", dept)

detail(name="Rahul", dept="HR")
detail(dept="HR", name="Rahul")
Output
Rahul works in HR Rahul works in HR

Default arguments

Give a parameter a value in the def line and it becomes optional.

Code
def detail(name, dept="Not assigned"):
    print(name, "-", dept)

detail("Rahul", "HR")
detail("Priya")              # dept falls back
Output
Rahul - HR Priya - Not assigned

*args

One star collects any number of positional arguments into a tuple.

Code
def total(*nums):
    print(nums, type(nums))
    return sum(nums)

print(total(10, 20))
print(total(10, 20, 30, 40))
Output
(10, 20) <class 'tuple'> 30 (10, 20, 30, 40) <class 'tuple'> 100

**kwargs

Two stars collect any number of named arguments into a dictionary.

Code
def record(**info):
    for k, v in info.items():
        print(k, "->", v)

record(name="Rahul", dept="HR", salary=47764)
Output
name -> Rahul dept -> HR salary -> 47764

Argument order

Positional first, then default, then *args, then **kwargs. Putting a default before a plain one is an error.

Code
def show(a, b=2, *args, **kwargs):
    print("a", a, "| b", b, "| args", args, "| kwargs", kwargs)

show(1)
show(1, 9)
show(1, 9, 100, 200, city="Chennai")
Output
a 1 | b 2 | args () | kwargs {} a 1 | b 9 | args () | kwargs {} a 1 | b 9 | args (100, 200) | kwargs {'city': 'Chennai'}
Practice — Function arguments
1. Write a function that takes a name and any number of subject marks, and prints the name with the total.
Show one way to do it
def report(name, *marks):
    print(name, "scored", sum(marks), "across", len(marks), "subjects")

report("Rahul", 45, 72, 88)
report("Priya", 91, 68)
Output
Rahul scored 205 across 3 subjects Priya scored 159 across 2 subjects
2. Write a function that accepts any number of named details and prints each one.
Show one way to do it
def profile(**d):
    for k, v in d.items():
        print(k, ":", v)

profile(name="Amit", city="Pune", exp=4)
Output
name : Amit city : Pune exp : 4

Lambda, map, filter and reduce

lambda

A function with no name, written on one line. Useful for a short, single-use function.

Code
double = lambda x: x * 2
print(double(21))

add = lambda a, b: a + b
print(add(10, 20))
Output
42 30

map()

Applies a function to EVERY item and gives back the same number of items.

Code
marks = [45, 72, 88]

out = map(lambda x: x + 5, marks)
print(list(out))

print(list(map(str, marks)))     # any function works
Output
[50, 77, 93] ['45', '72', '88']

filter()

Keeps only the items where the function says True. You get FEWER items back.

Code
marks = [45, 72, 88, 61, 33]

passed = filter(lambda x: x >= 60, marks)
print(list(passed))

print(list(filter(lambda x: x % 2 == 0, marks)))
Output
[72, 88, 61] [72, 88]

reduce()

Boils a whole list down to ONE value, two at a time. It has to be imported first.

Code
from functools import reduce

marks = [45, 72, 88]
print(reduce(lambda a, b: a + b, marks))
print(reduce(lambda a, b: a if a > b else b, marks))
Output
205 88

map, filter and reduce compared

map keeps the count, filter reduces the count, reduce collapses it to one.

Code
from functools import reduce
m = [45, 72, 88, 61]

print("map   ", list(map(lambda x: x * 2, m)), "   same count")
print("filter", list(filter(lambda x: x > 60, m)), "      fewer")
print("reduce", reduce(lambda a, b: a + b, m), "              one")
Output
map [90, 144, 176, 122] same count filter [72, 88, 61] fewer reduce 266 one
Practice — Lambda, map, filter and reduce
1. Using map, add 5 bonus marks to every mark in a list.
Show one way to do it
marks = [45, 72, 88, 61]
print(list(map(lambda x: x + 5, marks)))
Output
[50, 77, 93, 66]
2. Using filter, keep only the salaries above 50,000.
Show one way to do it
sal = [47764, 62990, 51200, 38000]
print(list(filter(lambda x: x > 50000, sal)))
Output
[62990, 51200]
3. Using reduce, find the product of [1, 2, 3, 4, 5].
Show one way to do it
from functools import reduce
print(reduce(lambda a, b: a * b, [1, 2, 3, 4, 5]))
Output
120

Recursion

Defining a recursive function

Every recursion needs a base case — the condition that stops it. Without one it never ends.

Code
def countdown(n):
    if n == 0:           # base case
        print("Go")
        return
    print(n, end=" ")
    countdown(n - 1)     # calls itself

countdown(5)
Output
5 4 3 2 1 Go

Factorial

5! is 5 x 4 x 3 x 2 x 1, and each step is the same problem one size smaller.

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

print(fact(5))
print(fact(7))
Output
120 5040

Fibonacci

Each number is the sum of the two before it. Two base cases this time.

Code
def fib(n):
    if n <= 1:
        return n
    return fib(n - 1) + fib(n - 2)

for i in range(10):
    print(fib(i), end=" ")
Output
0 1 1 2 3 5 8 13 21 34

A missing base case

Python raises RecursionError rather than running forever.

Code
import sys
sys.setrecursionlimit(100)

def forever(n):
    return forever(n - 1)      # nothing stops it

forever(5)
Output
RecursionError: maximum recursion depth exceeded
Practice — Recursion
1. Write a recursive function that adds up the numbers from 1 to n. Test it with 10.
Show one way to do it
def total(n):
    if n == 0:
        return 0
    return n + total(n - 1)

print(total(10))
Output
55
2. Write a recursive function that reverses a string.
Show one way to do it
def rev(s):
    if len(s) == 0:
        return ""
    return s[-1] + rev(s[:-1])

print(rev("analytics"))
Output
scitylana

Comprehensions

Basic syntax

A for loop and an append, written on one line. Read it as: what I want, then where it comes from.

Code
# the long way
squares = []
for n in range(1, 6):
    squares.append(n * n)
print(squares)

# the same thing
squares = [n * n for n in range(1, 6)]
print(squares)
Output
[1, 4, 9, 16, 25] [1, 4, 9, 16, 25]

With a condition

Put the if at the END and it filters — only the items that pass get built.

Code
marks = [45, 72, 88, 61, 33]

print([m for m in marks if m >= 60])
print([m * 2 for m in marks if m % 2 == 0])
Output
[72, 88, 61] [144, 176]

if and else inside a comprehension

When you want a value for EVERY item, the if-else goes at the FRONT.

Code
marks = [45, 72, 88, 61]

print(["pass" if m >= 60 else "fail" for m in marks])
Output
['fail', 'pass', 'pass', 'pass']

On strings, and nested

Anything you can loop over, you can comprehend over.

Code
print([c.upper() for c in "python"])
print([x for x in "statistics" if x in "aeiou"])
print([[i * j for j in range(1, 4)] for i in range(1, 4)])
Output
['P', 'Y', 'T', 'H', 'O', 'N'] ['a', 'i', 'i'] [[1, 2, 3], [2, 4, 6], [3, 6, 9]]

Dictionary comprehension

Same idea with curly brackets and a key : value pair.

Code
depts = ["HR", "Tech", "Sales"]
print({d: len(d) for d in depts})
print({n: n * n for n in range(1, 6)})
Output
{'HR': 2, 'Tech': 4, 'Sales': 5} {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
Practice — Comprehensions
1. Build a list of the squares of every even number from 1 to 20.
Show one way to do it
print([n * n for n in range(1, 21) if n % 2 == 0])
Output
[4, 16, 36, 64, 100, 144, 196, 256, 324, 400]
2. From ['HR','Tech','Sales'], build a list of the names in uppercase.
Show one way to do it
d = ["HR", "Tech", "Sales"]
print([x.upper() for x in d])
Output
['HR', 'TECH', 'SALES']
3. Label each mark 'pass' or 'fail' at a cut-off of 60, in one line.
Show one way to do it
m = [45, 72, 88, 61, 33]
print(["pass" if x >= 60 else "fail" for x in m])
Output
['fail', 'pass', 'pass', 'pass', 'fail']

String indexing and slicing

Indexing

A string is a sequence of characters. Counting starts at 0, and -1 is the last one.

Code
name = "Analytics"

print(name[0])
print(name[4])
print(name[-1])
print(len(name))
Output
A y s 9

Slicing

Take a piece. The stop is NOT included, so [0:4] gives characters 0, 1, 2 and 3.

Code
name = "Analytics"

print(name[0:4])
print(name[:4])
print(name[4:])
print(name[-3:])
Output
Anal Anal ytics ics

Step

How big a jump to take. A negative step walks backwards, which is how you reverse a string.

Code
name = "Analytics"

print(name[::2])
print(name[1::2])
print(name[::-1])        # reversed
Output
Aayis nltc scitylanA

Strings cannot be changed

Unlike a list, you cannot assign to one character. Build a new string instead.

Code
name = "Analytics"
name[0] = "X"
Output
TypeError: 'str' object does not support item assignment

Joining and repeating

+ joins two strings, * repeats one. Both make a NEW string.

Code
a, b = "Data", "Analytics"
print(a + " " + b)
print("-" * 20)
print(a * 3)
Output
Data Analytics -------------------- DataDataData

The in operator

Checks whether one string appears inside another. Hands back True or False.

Code
s = "Data Analytics"
print("Data" in s)
print("Python" in s)
print("data" in s)      # case matters
Output
True False False
Practice — String indexing and slicing
1. Take the string 'Data Analytics' and print it reversed, then print only the last five characters.
Show one way to do it
s = "Data Analytics"
print(s[::-1])
print(s[-5:])
Output
scitylanA ataD ytics
2. Check whether a word is a palindrome. Test it with 'madam' and with 'python'.
Show one way to do it
for w in ["madam", "python"]:
    print(w, w == w[::-1])
Output
madam True python False
3. Count the vowels in 'data analytics' without using count().
Show one way to do it
s = "data analytics"
n = 0
for ch in s:
    if ch in "aeiou":
        n = n + 1
print(n)
Output
5

String methods

Changing case

None of these change the original string; each returns a new one.

Code
s = "data analytics"
print(s.upper())
print(s.title())
print(s.capitalize())
print("HELLO".lower())
print(s)        # untouched
Output
DATA ANALYTICS Data Analytics Data analytics hello data analytics

strip()

Takes whitespace off both ends.

Code
s = "   Rahul Sharma   "
print("[" + s + "]")
print("[" + s.strip() + "]")
print("[" + s.lstrip() + "]")
print("[" + s.rstrip() + "]")
Output
[ Rahul Sharma ] [Rahul Sharma] [Rahul Sharma ] [ Rahul Sharma]

replace()

Swaps every occurrence of one piece of text for another.

Code
s = "Data Analytics"
print(s.replace("Data", "Business"))
print("a-b-c".replace("-", " "))
print(s.replace("a", "*"))
Output
Business Analytics a b c D*t* An*lytics

split() and join()

split cuts a string into a list; join glues a list back into a string. Opposites.

Code
s = "HR,Tech,Sales"
parts = s.split(",")
print(parts)

print(" | ".join(parts))
print("Rahul Kumar Sharma".split())     # no argument = split on spaces
Output
['HR', 'Tech', 'Sales'] HR | Tech | Sales ['Rahul', 'Kumar', 'Sharma']

find() and count()

find gives the POSITION of the first match, or -1 if it is not there. count gives how many.

Code
s = "statistics"
print(s.find("t"))
print(s.find("z"))        # -1, not an error
print(s.count("t"))
print(s.count("s"))
Output
1 -1 3 3

startswith / endswith

Checks the beginning or the end. Commonly used for filenames and codes.

Code
f = "employees.csv"
print(f.endswith(".csv"))
print(f.startswith("emp"))
print("EMP1001".startswith("EMP"))
Output
True True True

The is-checks

Each one asks a yes/no question about what the string contains.

Code
print("12345".isdigit())
print("Rahul".isalpha())
print("Rahul123".isalnum())
print("   ".isspace())
print("HELLO".isupper())
Output
True True True True True
Practice — String methods
1. A name arrives as ' rahul SHARMA '. Clean it up so it reads 'Rahul Sharma'.
Show one way to do it
raw = "   rahul SHARMA  "
print("[" + raw.strip().title() + "]")
Output
[Rahul Sharma]
2. Split 'HR,Tech,Sales,Marketing' into a list, then join it back with ' | '.
Show one way to do it
s = "HR,Tech,Sales,Marketing"
parts = s.split(",")
print(parts)
print(" | ".join(parts))
Output
['HR', 'Tech', 'Sales', 'Marketing'] HR | Tech | Sales | Marketing
3. Count how many times each letter appears in 'statistics' and print the most common one.
Show one way to do it
w = "statistics"
c = {}
for ch in w:
    c[ch] = c.get(ch, 0) + 1
print(c)
print("most common:", max(c, key=c.get))
Output
{'s': 3, 't': 3, 'a': 1, 'i': 2, 'c': 1} most common: s

String formatting

f-strings

An f before the quote allows an expression inside curly brackets.

Code
name, dept, salary = "Rahul", "HR", 47764

print(f"{name} works in {dept} and earns {salary}")
print(f"next year: {salary * 1.1}")
Output
Rahul works in HR and earns 47764 next year: 52540.4

Rounding

:.2f sets the number of decimal places.

Code
salary = 47764
hiked = salary * 1.1

print(f"raw     {hiked}")
print(f"rounded {hiked:.2f}")
print(f"no dp   {hiked:.0f}")
Output
raw 52540.4 rounded 52540.40 no dp 52540

Alignment

A number after <, > or ^ sets the field width.

Code
rows = [("HR", 45), ("Marketing", 42), ("Tech", 49)]

for d, n in rows:
    print(f"{d:<12}{n:>5}")
Output
HR 45 Marketing 42 Tech 49

format()

The curly brackets are filled in order.

Code
print("{} works in {}".format("Rahul", "HR"))
print("{1} then {0}".format("second", "first"))
print("{:.2f}".format(3.14159))
Output
Rahul works in HR first then second 3.14
Practice — String formatting
1. Print a small table of three departments and their headcounts, with the numbers lined up.
Show one way to do it
rows = [("HR", 45), ("Marketing", 42), ("Tech", 49)]
for d, n in rows:
    print(f"{d:<12}{n:>4}")
Output
HR 45 Marketing 42 Tech 49
2. A salary of 47764 gets a 12% hike. Print the new salary to two decimal places using an f-string.
Show one way to do it
s = 47764
print(f"new salary: {s * 1.12:.2f}")
Output
new salary: 53495.68

Regular expressions

Meta characters

A character that stands for a class of characters rather than itself.

Code
print(r"\d   any digit 0-9")
print(r"\w   any letter, digit or underscore")
print(r"\s   any space, tab or newline")
print(r".    any character at all")
print(r"^    start of the string")
print(r"$    end of the string")
print(r"+    one or more")
print(r"*    zero or more")
print(r"?    zero or one")
print(r"{n}  exactly n of them")
Output
\d any digit 0-9 \w any letter, digit or underscore \s any space, tab or newline . any character at all ^ start of the string $ end of the string + one or more * zero or more ? zero or one {n} exactly n of them

re.findall()

Returns every match as a list.

Code
import re

s = "Rahul 1001, Priya 1002, Amit 1003"
print(re.findall(r"\d+", s))
print(re.findall(r"[A-Z][a-z]+", s))
Output
['1001', '1002', '1003'] ['Rahul', 'Priya', 'Amit']

re.search()

Finds the FIRST match anywhere and hands back a match object, or None.

Code
import re

s = "Employee ID is EMP1001"
m = re.search(r"EMP\d+", s)
print(m)
print(m.group())
print(re.search(r"XYZ", s))      # None
Output
<re.Match object; span=(15, 22), match='EMP1001'> EMP1001 None

re.match()

Same as search, but it only looks at the beginning of the string.

Code
import re

print(re.match(r"EMP", "EMP1001"))
print(re.match(r"1001", "EMP1001"))     # None - not at the start
Output
<re.Match object; span=(0, 3), match='EMP'> None

re.sub()

Replaces every match with something else. A find-and-replace that understands patterns.

Code
import re

s = "Call 9876543210 or 9123456789"
print(re.sub(r"\d", "X", s))
print(re.sub(r"\d{10}", "[hidden]", s))
Output
Call XXXXXXXXXX or XXXXXXXXXX Call [hidden] or [hidden]

re.split()

Splits on a pattern rather than on one fixed character.

Code
import re

print(re.split(r"[,;]", "HR,Tech;Sales,Marketing"))
print(re.split(r"\s+", "too    many     spaces"))
Output
['HR', 'Tech', 'Sales', 'Marketing'] ['too', 'many', 'spaces']

Validating an email

^ and $ anchor the pattern so the whole string must match.

Code
import re

pattern = r"^[\w.]+@[\w]+\.[a-z]{2,}$"

for e in ["rahul@tap.com", "priya.s@tap.co.in", "not-an-email", "a@b"]:
    print(e.ljust(20), bool(re.match(pattern, e)))
Output
rahul@tap.com True priya.s@tap.co.in False not-an-email False a@b False
Practice — Regular expressions
1. Pull every number out of 'Order 12 shipped on 2026-10-30 for 450 rupees'.
Show one way to do it
import re
print(re.findall(r"\d+", "Order 12 shipped on 2026-10-30 for 450 rupees"))
Output
['12', '2026', '10', '30', '450']
2. Hide every 10-digit phone number in a line of text.
Show one way to do it
import re
s = "Call 9876543210 or 9123456789 today"
print(re.sub(r"\d{10}", "[hidden]", s))
Output
Call [hidden] or [hidden] today
3. Check which of these are valid employee IDs in the form EMP followed by exactly four digits.
Show one way to do it
import re
for x in ["EMP1001", "EMP10", "emp1001", "EMP12345"]:
    print(x.ljust(10), bool(re.match(r"^EMP\d{4}$", x)))
Output
EMP1001 True EMP10 False emp1001 False EMP12345 False

File handling

open() and file modes

"w" writes and WIPES whatever was there. "a" adds to the end. "r" reads. Choose carefully.

Code
f = open("notes.txt", "w")
f.write("first line\n")
f.write("second line\n")
f.close()

f = open("notes.txt", "r")
print(f.read())
f.close()
Output
first line second line

Write mode overwrites

Opening in w mode empties the file before you write a single thing.

Code
open("data.txt", "w").write("original content\n")

open("data.txt", "w").write("new content\n")   # the original is GONE

print(open("data.txt").read())
Output
new content

Append mode

Append mode keeps what is already there and writes underneath it.

Code
open("log.txt", "w").write("line 1\n")
open("log.txt", "a").write("line 2\n")
open("log.txt", "a").write("line 3\n")

print(open("log.txt").read())
Output
line 1 line 2 line 3

read, readline and readlines

read gives one big string, readline gives one line, readlines gives a list of lines.

Code
open("f.txt", "w").write("alpha\nbeta\ngamma\n")

f = open("f.txt")
print(repr(f.readline()))
f.close()

f = open("f.txt")
print(f.readlines())
f.close()
Output
'alpha\n' ['alpha\n', 'beta\n', 'gamma\n']

Reading line by line

The normal way to read a file line by line. strip() takes the newline off each one.

Code
open("f.txt", "w").write("HR\nTech\nSales\n")

f = open("f.txt")
for line in f:
    print("[" + line.strip() + "]")
f.close()
Output
[HR] [Tech] [Sales]

with open()

The file is closed automatically, even if the code inside fails.

Code
with open("f.txt", "w") as f:
    f.write("written safely\n")

with open("f.txt") as f:
    print(f.read().strip())

print("file closed?", f.closed)
Output
written safely file closed? True
Practice — File handling
1. Write three department names to a file, then read it back and print each one without the newline.
Show one way to do it
with open("d.txt", "w") as f:
    for d in ["HR", "Tech", "Sales"]:
        f.write(d + "\n")

with open("d.txt") as f:
    for line in f:
        print("[" + line.strip() + "]")
Output
[HR] [Tech] [Sales]
2. Append two more lines to an existing file and print how many lines it has in total.
Show one way to do it
open("d.txt", "w").write("HR\nTech\n")
with open("d.txt", "a") as f:
    f.write("Sales\n")
    f.write("Marketing\n")
print(len(open("d.txt").readlines()), "lines")
Output
4 lines
3. Read a file of numbers, one per line, and print their total.
Show one way to do it
open("n.txt", "w").write("10\n20\n30\n")
total = 0
with open("n.txt") as f:
    for line in f:
        total = total + int(line.strip())
print(total)
Output
60

Exception handling

An unhandled error

An uncaught error stops the program; nothing after it runs.

Code
nums = ["10", "20", "abc", "30"]

for n in nums:
    print(int(n))      # stops dead on "abc"
Output
10 20 ValueError: invalid literal for int() with base 10: 'abc'

try and except

Try the risky line. If it fails, run the except block instead of stopping.

Code
nums = ["10", "20", "abc", "30"]

for n in nums:
    try:
        print(int(n))
    except:
        print(n, "is not a number - skipped")
Output
10 20 abc is not a number - skipped 30

Catching a specific error

Naming the error avoids hiding problems you did not expect.

Code
def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        return "cannot divide by zero"

print(divide(10, 2))
print(divide(10, 0))
Output
5.0 cannot divide by zero

Multiple except blocks

Different problems, different handling. Python runs the first one that matches.

Code
for value, divisor in [("10", 2), ("abc", 2), ("10", 0)]:
    try:
        print(int(value) / divisor)
    except ValueError:
        print("not a number:", value)
    except ZeroDivisionError:
        print("divisor was zero")
Output
5.0 not a number: abc divisor was zero

else and finally

else runs only when nothing failed. finally runs either way — it is where you clean up.

Code
def read(n):
    try:
        v = int(n)
    except ValueError:
        print("bad input")
    else:
        print("worked:", v)
    finally:
        print("-- done --")

read("25")
read("xyz")
Output
worked: 25 -- done -- bad input -- done --

Common exceptions

The exception name identifies what went wrong.

Code
tests = [lambda: int("abc"),
         lambda: 10 / 0,
         lambda: [1, 2, 3][9],
         lambda: {"a": 1}["b"],
         lambda: "5" + 5]

for t in tests:
    try:
        t()
    except Exception as e:
        print(type(e).__name__, "-", e)
Output
ValueError - invalid literal for int() with base 10: 'abc' ZeroDivisionError - division by zero IndexError - list index out of range KeyError - 'b' TypeError - can only concatenate str (not "int") to str
Practice — Exception handling
1. Ask for a number and keep going even if the user types text instead.
Show one way to do it
for entry in ["25", "hello"]:
    try:
        print("doubled:", int(entry) * 2)
    except ValueError:
        print(entry, "is not a number")
Output
doubled: 50 hello is not a number
2. Write a safe divide function that handles both a zero divisor and a non-numeric input.
Show one way to do it
def safe(a, b):
    try:
        return int(a) / int(b)
    except ZeroDivisionError:
        return "cannot divide by zero"
    except ValueError:
        return "give me numbers"

print(safe(10, 2))
print(safe(10, 0))
print(safe("x", 2))
Output
5.0 cannot divide by zero give me numbers
3. Try to open a file that does not exist and print a friendly message instead of crashing.
Show one way to do it
try:
    with open("missing.txt") as f:
        print(f.read())
except FileNotFoundError:
    print("that file is not here")
Output
that file is not here

Classes and objects

Defining a class

A class is a blueprint; an object is one instance built from it.

Code
class Employee:
    pass

e1 = Employee()
e2 = Employee()
print(type(e1))
print(e1 is e2)      # two different objects
Output
<class '__main__.Employee'> False

__init__ and self

__init__ runs when an object is created. self refers to that object.

Code
class Employee:
    def __init__(self, name, dept, salary):
        self.name = name
        self.dept = dept
        self.salary = salary

e = Employee("Rahul", "HR", 47764)
print(e.name, e.dept, e.salary)
Output
Rahul HR 47764

Methods

A function defined inside a class. It takes self as its first parameter.

Code
class Employee:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary

    def hike(self, pct):
        self.salary = self.salary + self.salary * pct / 100
        return self.salary

    def show(self):
        print(self.name, "earns", self.salary)

e = Employee("Rahul", 47764)
e.show()
e.hike(10)
e.show()
Output
Rahul earns 47764 Rahul earns 52540.4

Each object has its own data

Two objects created from the same class do not share their data.

Code
class Employee:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary

a = Employee("Rahul", 47764)
b = Employee("Priya", 62990)

a.salary = 50000
print(a.name, a.salary)
print(b.name, b.salary)     # untouched
Output
Rahul 50000 Priya 62990

Objects in a list

Objects in a list can be looped over like any other data.

Code
class Employee:
    def __init__(self, name, dept, salary):
        self.name, self.dept, self.salary = name, dept, salary

staff = [Employee("Rahul", "HR", 47764),
         Employee("Priya", "Tech", 62990),
         Employee("Amit", "Sales", 51200)]

for e in staff:
    print(e.name.ljust(8), e.dept.ljust(7), e.salary)

total = sum(e.salary for e in staff)
print("total payroll:", total)
print("average      :", total / len(staff))
Output
Rahul HR 47764 Priya Tech 62990 Amit Sales 51200 total payroll: 161954 average : 53984.666666666664

Filtering a list of objects

List operations apply the same way when the items are objects.

Code
class Employee:
    def __init__(self, name, dept, salary):
        self.name, self.dept, self.salary = name, dept, salary

staff = [Employee("Rahul", "HR", 47764),
         Employee("Priya", "Tech", 62990),
         Employee("Amit", "Tech", 51200)]

tech = [e for e in staff if e.dept == "Tech"]
for e in tech:
    print(e.name)

print("highest paid:", max(staff, key=lambda e: e.salary).name)
Output
Priya Amit highest paid: Priya
Practice — Classes and objects
1. Build a Student class with name and three marks, and a method that returns the average.
Show one way to do it
class Student:
    def __init__(self, name, m1, m2, m3):
        self.name = name
        self.marks = [m1, m2, m3]

    def average(self):
        return sum(self.marks) / len(self.marks)

s = Student("Rahul", 45, 72, 88)
print(s.name, "->", s.average())
Output
Rahul -> 68.33333333333333
2. Make a list of four Employee objects and print the one with the highest salary.
Show one way to do it
class Employee:
    def __init__(self, name, salary):
        self.name, self.salary = name, salary

staff = [Employee("Rahul", 47764), Employee("Priya", 62990),
         Employee("Amit", 51200), Employee("Kavya", 58300)]

top = max(staff, key=lambda e: e.salary)
print(top.name, top.salary)
Output
Priya 62990
3. From a list of Employee objects, print the average salary of the Tech department only.
Show one way to do it
class Employee:
    def __init__(self, name, dept, salary):
        self.name, self.dept, self.salary = name, dept, salary

staff = [Employee("Rahul", "HR", 47764), Employee("Priya", "Tech", 62990),
         Employee("Amit", "Tech", 51200)]

tech = [e.salary for e in staff if e.dept == "Tech"]
print(sum(tech) / len(tech))
Output
57095.0

The four pillars of OOP

Encapsulation

The data and the methods that use it live in the same class. Two leading underscores mark an attribute as internal.

Code
class Account:
    def __init__(self, holder, balance):
        self.holder   = holder
        self.__balance = balance        # internal

    def deposit(self, amount):
        self.__balance = self.__balance + amount

    def show(self):
        print(self.holder, "balance:", self.__balance)

a = Account("Rahul", 1000)
a.deposit(500)
a.show()
print(hasattr(a, "__balance"))      # not reachable from outside
Output
Rahul balance: 1500 False

Inheritance

Naming a parent class in the brackets gives the child all of its attributes and methods.

Code
class Employee:
    def __init__(self, name):
        self.name = name

    def show(self):
        print("Employee:", self.name)

class Manager(Employee):          # inherits
    pass

m = Manager("Priya")
m.show()                          # a method it never defined
print(isinstance(m, Employee))
Output
Employee: Priya True

super()

Calls the parent's version, so it does not have to be rewritten.

Code
class Employee:
    def __init__(self, name):
        self.name = name

class Manager(Employee):
    def __init__(self, name, team):
        super().__init__(name)        # reuse the parent
        self.team = team

m = Manager("Priya", 6)
print(m.name, "manages", m.team, "people")
Output
Priya manages 6 people

Polymorphism

The child defines a method the parent already has. Same name, different behaviour.

Code
class Employee:
    def role(self):
        print("does the work")

class Manager(Employee):
    def role(self):               # overrides
        print("assigns the work")

class Intern(Employee):
    pass                          # keeps the parent version

for p in [Employee(), Manager(), Intern()]:
    p.role()
Output
does the work assigns the work does the work

Abstraction

A base class names a method and leaves the detail to each child class.

Code
class Payroll:
    def calculate(self):
        pass                      # the parent only NAMES it

class Monthly(Payroll):
    def calculate(self):
        return 50000

class Hourly(Payroll):
    def calculate(self):
        return 250 * 160

for p in [Monthly(), Hourly()]:
    print(type(p).__name__, "->", p.calculate())
Output
Monthly -> 50000 Hourly -> 40000
Practice — The four pillars of OOP
1. Make a Vehicle class with a method describe(), then a Car class that overrides it.
Show one way to do it
class Vehicle:
    def describe(self):
        print("a vehicle that moves")

class Car(Vehicle):
    def describe(self):
        print("a car with four wheels")

for v in [Vehicle(), Car()]:
    v.describe()
Output
a vehicle that moves a car with four wheels
2. Make a Manager class that inherits Employee and adds a team size, reusing the parent's __init__ with super().
Show one way to do it
class Employee:
    def __init__(self, name, salary):
        self.name, self.salary = name, salary
    def show(self):
        print(self.name, self.salary)

class Manager(Employee):
    def __init__(self, name, salary, team):
        super().__init__(name, salary)
        self.team = team
    def show(self):
        super().show()
        print("  manages", self.team, "people")

Manager("Priya", 90000, 6).show()
Output
Priya 90000 manages 6 people

Creating arrays

np.array()

Builds an array from a list. An array holds one type of value and prints without commas.

Code
import numpy as np
a = np.array([10, 20, 30, 40])
print(a)
print(type(a))
Output
[10 20 30 40] <class 'numpy.ndarray'>

Two dimensions

A list of lists becomes a table: rows inside, columns across.

Code
import numpy as np
m = np.array([[1, 2, 3],
              [4, 5, 6]])
print(m)
Output
[[1 2 3] [4 5 6]]

np.arange()

A sequence of numbers. Takes start, stop and step; the stop value is not included.

Code
import numpy as np
print(np.arange(5))
print(np.arange(1, 11))
print(np.arange(0, 21, 5))
Output
[0 1 2 3 4] [ 1 2 3 4 5 6 7 8 9 10] [ 0 5 10 15 20]

np.zeros() and np.ones()

Arrays filled with 0 or 1. Both produce floats unless a type is given.

Code
import numpy as np
print(np.zeros(5))
print(np.ones(4))
print(np.zeros((2, 3)))
Output
[0. 0. 0. 0. 0.] [1. 1. 1. 1.] [[0. 0. 0.] [0. 0. 0.]]

np.full()

An array of any size filled with a value of your choice.

Code
import numpy as np
print(np.full(5, 7))
print(np.full((2, 3), -1))
Output
[7 7 7 7 7] [[-1 -1 -1] [-1 -1 -1]]

np.linspace()

Evenly spaced values between two points. The third number is how many you want, not the step.

Code
import numpy as np
print(np.linspace(0, 10, 5))
print(np.linspace(0, 1, 3))
Output
[ 0. 2.5 5. 7.5 10. ] [0. 0.5 1. ]

np.random

Random values. rand gives decimals between 0 and 1; randint gives whole numbers in a range.

Code
import numpy as np
np.random.seed(1)            # fixes the result so it can be checked
print(np.random.rand(3))
print(np.random.randint(1, 100, 5))
Output
[4.17022005e-01 7.20324493e-01 1.14374817e-04] [76 6 80 65 17]
Practice — Creating arrays
1. Create an array of every even number from 0 to 20, and a 3x3 array filled with 1.
Show one way to do it
import numpy as np
print(np.arange(0, 21, 2))
print(np.ones((3, 3)))
Output
[ 0 2 4 6 8 10 12 14 16 18 20] [[1. 1. 1.] [1. 1. 1.] [1. 1. 1.]]

Inspecting an array

ndim, shape, size

How many dimensions, the rows and columns, and the total number of values. No brackets.

Code
import numpy as np
m = np.array([[1, 2, 3],
              [4, 5, 6]])
print(m.ndim)
print(m.shape)
print(m.size)
Output
2 (2, 3) 6

dtype

The single type every value in the array shares.

Code
import numpy as np
print(np.array([1, 2, 3]).dtype)
print(np.array([1.5, 2.5]).dtype)
print(np.array(["a", "b"]).dtype)
Output
int64 float64 <U1

astype()

Converts the array to another type. Converting a float to an int removes the decimal part.

Code
import numpy as np
a = np.array([1.7, 2.3, 3.9])
print(a.astype(int))
print(np.array([1, 2, 3]).astype(float))
Output
[1 2 3] [1. 2. 3.]
Practice — Inspecting an array
1. For a 3x4 array of zeros, print its dimensions, shape, size and dtype.
Show one way to do it
import numpy as np
a = np.zeros((3, 4))
print(a.ndim, a.shape, a.size, a.dtype)
Output
2 (3, 4) 12 float64

Accessing elements

Indexing

Position 0 is the first value. Negative positions count back from the end.

Code
import numpy as np
a = np.array([10, 20, 30, 40, 50])
print(a[0])
print(a[3])
print(a[-1])
Output
10 40 50

Slicing

a[start:stop] returns a range of values. The stop position is not included.

Code
import numpy as np
a = np.array([10, 20, 30, 40, 50])
print(a[1:4])
print(a[:3])
print(a[2:])
print(a[-2:])
Output
[20 30 40] [10 20 30] [30 40 50] [40 50]

Step

A third number sets the jump. A negative step reverses the array.

Code
import numpy as np
a = np.array([10, 20, 30, 40, 50])
print(a[::2])
print(a[1::2])
print(a[::-1])
Output
[10 30 50] [20 40] [50 40 30 20 10]

Two dimensions

Give the row first, then the column. A colon on its own means every row or every column.

Code
import numpy as np
m = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 9]])
print(m[0])
print(m[1, 2])
print(m[:, 0])
print(m[0:2, 0:2])
Output
[1 2 3] 6 [1 4 7] [[1 2] [4 5]]
Practice — Accessing elements
1. From [10,20,30,40,50,60] print the first three, the last two, and the array reversed.
Show one way to do it
import numpy as np
a = np.array([10, 20, 30, 40, 50, 60])
print(a[:3])
print(a[-2:])
print(a[::-1])
Output
[10 20 30] [50 60] [60 50 40 30 20 10]
2. From a 3x3 array, print the middle column and the top-left 2x2 block.
Show one way to do it
import numpy as np
m = np.array([[1,2,3],[4,5,6],[7,8,9]])
print(m[:, 1])
print(m[0:2, 0:2])
Output
[2 5 8] [[1 2] [4 5]]

Array operations

Arithmetic

An operator applies to every element at once. No loop is needed.

Code
import numpy as np
a = np.array([10, 20, 30, 40])
print(a + 5)
print(a - 5)
print(a * 2)
print(a / 10)
Output
[15 25 35 45] [ 5 15 25 35] [20 40 60 80] [1. 2. 3. 4.]

Operations return a new array

These operations return a new array. The original is unchanged until you assign the result.

Code
import numpy as np
a = np.array([10, 20, 30])
a + 5
print(a)
a = a + 5
print(a)
Output
[10 20 30] [15 25 35]

Two arrays

Operators work position by position when the arrays are the same size.

Code
import numpy as np
a = np.array([10, 20, 30])
b = np.array([1, 2, 3])
print(a + b)
print(a * b)
Output
[11 22 33] [10 40 90]

np.sqrt() and np.round()

Maths functions take the array as an argument. The second number of round is the decimal places.

Code
import numpy as np
a = np.array([9, 16, 25, 36])
print(np.sqrt(a))
print(np.round(a / 3))
print(np.round(a / 3, 2))
Output
[3. 4. 5. 6.] [ 3. 5. 8. 12.] [ 3. 5.33 8.33 12. ]
Practice — Array operations
1. Give every value in [45000, 52000, 61000] a 10 percent increase.
Show one way to do it
import numpy as np
s = np.array([45000, 52000, 61000])
print(s * 1.10)
Output
[49500. 57200. 67100.]

Aggregation

sum, mean, min and max

Reduce a whole array to a single value.

Code
import numpy as np
a = np.array([15, 8, 42, 4, 23])
print(a.sum())
print(a.mean())
print(a.min())
print(a.max())
Output
92 18.4 4 42

np.median()

The middle value. It is a NumPy function, not a method on the array.

Code
import numpy as np
a = np.array([15, 8, 42, 4, 23])
print(np.median(a))
Output
15.0

std and var

Standard deviation measures spread. Variance is the square of it.

Code
import numpy as np
a = np.array([15, 8, 42, 4, 23])
print(round(a.std(), 2))
print(round(a.var(), 2))
Output
13.46 181.04

argmin and argmax

The position of the smallest or largest value, not the value itself.

Code
import numpy as np
a = np.array([15, 8, 42, 4, 23])
print(a.min(), a.argmin())
print(a.max(), a.argmax())
Output
4 3 42 2

cumsum()

A running total. The final value equals the sum of the whole array.

Code
import numpy as np
a = np.array([10, 20, 30, 40])
print(a.cumsum())
print(a.sum())
Output
[ 10 30 60 100] 100

axis

On a table, axis=0 works down the columns and axis=1 works across the rows.

Code
import numpy as np
m = np.array([[10, 20, 30],
              [40, 50, 60]])
print(m.sum())
print(m.sum(axis=0))
print(m.sum(axis=1))
print(m.mean(axis=1))
Output
210 [50 70 90] [ 60 150] [20. 50.]
Practice — Aggregation
1. For [23, 45, 12, 67, 34, 89] print the total, average, highest and its position.
Show one way to do it
import numpy as np
a = np.array([23, 45, 12, 67, 34, 89])
print(a.sum(), round(a.mean(), 2))
print(a.max(), a.argmax())
Output
270 45.0 89 5
2. For a 2x3 table print the total of each column and the average of each row.
Show one way to do it
import numpy as np
m = np.array([[10,20,30],[40,50,60]])
print(m.sum(axis=0))
print(m.mean(axis=1))
Output
[50 70 90] [20. 50.]

Broadcasting

With a single value

One number is applied to every element of the array.

Code
import numpy as np
m = np.array([[10, 20, 30],
              [40, 50, 60]])
print(m + 100)
Output
[[110 120 130] [140 150 160]]

With a row

A one-row array is reused for every row of the table when the widths match.

Code
import numpy as np
m = np.array([[10, 20, 30],
              [40, 50, 60]])
r = np.array([1, 2, 3])
print(m + r)
Output
[[11 22 33] [41 52 63]]

Mismatched shapes

The sizes must match or be 1. If they do not, NumPy stops and names both shapes.

Code
import numpy as np
m = np.array([[10, 20, 30],
              [40, 50, 60]])
print(m + np.array([1, 2]))
Output
ValueError: operands could not be broadcast together with shapes (2,3) (2,)
Practice — Broadcasting
1. Add [1, 2, 3] to every row of a 3x3 table.
Show one way to do it
import numpy as np
m = np.array([[10,20,30],[40,50,60],[70,80,90]])
print(m + np.array([1, 2, 3]))
Output
[[11 22 33] [41 52 63] [71 82 93]]

Filtering

A condition returns booleans

Comparing an array to a value tests every element and returns an array of booleans.

Code
import numpy as np
a = np.array([5, 12, 18, 7, 25])
print(a > 10)
Output
[False True True False True]

Selecting with a condition

Putting the condition inside the brackets returns only the values where it was True.

Code
import numpy as np
a = np.array([5, 12, 18, 7, 25])
print(a[a > 10])
print(a[a % 2 == 0])
Output
[12 18 25] [12 18]

Counting matches

True counts as 1, so summing the condition counts how many values matched.

Code
import numpy as np
a = np.array([5, 12, 18, 7, 25])
print((a > 10).sum())
Output
3

Two conditions

Use & for and, | for or. Each condition needs its own brackets.

Code
import numpy as np
a = np.array([5, 12, 18, 7, 25])
print(a[(a > 10) & (a < 20)])
print(a[(a < 8) | (a > 20)])
Output
[12 18] [ 5 7 25]

np.where()

Takes a condition, a value for True and a value for False. The array keeps its length.

Code
import numpy as np
a = np.array([5, 12, 18, 7, 25])
print(np.where(a > 10, "high", "low"))
print(np.where(a > 10, a, 0))
Output
['low' 'high' 'high' 'low' 'high'] [ 0 12 18 0 25]
Practice — Filtering
1. From [12, 45, 7, 88, 23, 56] print the values above 20, and count how many there are.
Show one way to do it
import numpy as np
a = np.array([12, 45, 7, 88, 23, 56])
print(a[a > 20])
print((a > 20).sum())
Output
[45 88 23 56] 4
2. Label each value in [12, 45, 7, 88] as pass or fail at a cut-off of 40.
Show one way to do it
import numpy as np
a = np.array([12, 45, 7, 88])
print(np.where(a >= 40, "pass", "fail"))
Output
['fail' 'pass' 'fail' 'pass']

Sorting

np.sort()

Returns the values in order, smallest first. The original array is unchanged.

Code
import numpy as np
a = np.array([15, 8, 42, 4, 23])
print(np.sort(a))
print(a)
Output
[ 4 8 15 23 42] [15 8 42 4 23]

np.argsort()

Returns the positions that would put the array in order.

Code
import numpy as np
a = np.array([15, 8, 42, 4, 23])
print(np.argsort(a))
print(a[np.argsort(a)])
Output
[3 1 0 4 2] [ 4 8 15 23 42]

np.unique()

The distinct values, in order, with repeats removed.

Code
import numpy as np
a = np.array([3, 1, 2, 3, 1, 1, 4])
print(np.unique(a))
Output
[1 2 3 4]
Practice — Sorting
1. Sort [5, 2, 9, 1, 7] and also print the positions that would sort it.
Show one way to do it
import numpy as np
a = np.array([5, 2, 9, 1, 7])
print(np.sort(a))
print(np.argsort(a))
Output
[1 2 5 7 9] [3 1 0 4 2]

Changing shape

reshape()

Rearranges the same values into different rows and columns. Rows x columns must equal size.

Code
import numpy as np
a = np.arange(1, 7)
print(a.reshape(2, 3))
print(a.reshape(3, 2))
Output
[[1 2 3] [4 5 6]] [[1 2] [3 4] [5 6]]

reshape must match the size

If the new shape needs a different number of values, NumPy refuses.

Code
import numpy as np
a = np.arange(1, 7)
print(a.reshape(4, 2))
Output
ValueError: cannot reshape array of size 6 into shape (4,2)

flatten()

Turns a table back into a single row. It returns a copy, so the original is unchanged.

Code
import numpy as np
m = np.arange(1, 7).reshape(2, 3)
print(m.flatten())
print(m)
Output
[1 2 3 4 5 6] [[1 2 3] [4 5 6]]
Practice — Changing shape
1. Turn the numbers 1 to 12 into a 3x4 table, then flatten it back.
Show one way to do it
import numpy as np
a = np.arange(1, 13)
m = a.reshape(3, 4)
print(m)
print(m.flatten())
Output
[[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12]] [ 1 2 3 4 5 6 7 8 9 10 11 12]

Series and DataFrame

pd.Series()

A single column of values. Pandas adds a numbered index on the left.

Code
import pandas as pd
s = pd.Series([10, 20, 30])
print(s)
Output
0 10 1 20 2 30 dtype: int64

A custom index

The index can be any set of labels instead of 0, 1, 2.

Code
import pandas as pd
s = pd.Series([10, 20, 30], index=["a", "b", "c"])
print(s)
print(s["b"])
Output
a 10 b 20 c 30 dtype: int64 20

pd.DataFrame()

A table. Built from a dictionary, each key becomes a column name.

Code
import pandas as pd
df = pd.DataFrame({
    "name": ["Rahul", "Priya"],
    "dept": ["HR", "Tech"]
})
print(df)
Output
name dept 0 Rahul HR 1 Priya Tech

read_csv()

Loads a comma-separated file into a DataFrame.

Code
import pandas as pd
open("staff.csv", "w").write("name,dept\nRahul,HR\nPriya,Tech\n")

df = pd.read_csv("staff.csv")
print(df)
Output
name dept 0 Rahul HR 1 Priya Tech
Practice — Series and DataFrame
1. Build a DataFrame of three students with a name, a city and a mark, and print it.
Show one way to do it
import pandas as pd
df = pd.DataFrame({
    "name": ["Anita", "Rohit", "Meena"],
    "city": ["Chennai", "Pune", "Delhi"],
    "mark": [72, 85, 64]
})
print(df)
Output
name city mark 0 Anita Chennai 72 1 Rohit Pune 85 2 Meena Delhi 64

Inspecting a DataFrame

head() and tail()

The first or last rows. The default is five; pass a number for more or fewer.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df.head(3))
print()
print(df.tail(2))
Output
name dept salary exp 0 Rahul HR 47764 4 1 Priya Tech 62990 7 2 Amit Sales 51200 3 name dept salary exp 3 Kavya Tech 58300 6 4 Arjun HR 45100 2

shape, columns, dtypes

The number of rows and columns, the column names, and the type held in each.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df.shape)
print(list(df.columns))
print(df.dtypes)
Output
(5, 4) ['name', 'dept', 'salary', 'exp'] name object dept object salary int64 exp int64 dtype: object

info()

Column names, their types and how many non-empty values each one holds.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

df.info()
Output
<class 'pandas.core.frame.DataFrame'> RangeIndex: 5 entries, 0 to 4 Data columns (total 4 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 name 5 non-null object 1 dept 5 non-null object 2 salary 5 non-null int64 3 exp 5 non-null int64 dtypes: int64(2), object(2) memory usage: 288.0+ bytes

describe()

Count, mean, standard deviation, minimum, quartiles and maximum for the numeric columns.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df.describe())
Output
salary exp count 5.000000 5.000000 mean 53070.800000 4.400000 std 7431.869428 2.073644 min 45100.000000 2.000000 25% 47764.000000 3.000000 50% 51200.000000 4.000000 75% 58300.000000 6.000000 max 62990.000000 7.000000
Practice — Inspecting a DataFrame
1. Print the shape, the column names and the summary statistics of a table.
Show one way to do it
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df.shape)
print(list(df.columns))
print(df.describe())
Output
(5, 4) ['name', 'dept', 'salary', 'exp'] salary exp count 5.000000 5.000000 mean 53070.800000 4.400000 std 7431.869428 2.073644 min 45100.000000 2.000000 25% 47764.000000 3.000000 50% 51200.000000 4.000000 75% 58300.000000 6.000000 max 62990.000000 7.000000

Selecting columns

One column

Square brackets with the column name return that column as a Series.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df["name"])
Output
0 Rahul 1 Priya 2 Amit 3 Kavya 4 Arjun Name: name, dtype: object

Several columns

Two or more column names must be passed as a list, so there are two sets of brackets.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df[["name", "salary"]])
Output
name salary 0 Rahul 47764 1 Priya 62990 2 Amit 51200 3 Kavya 58300 4 Arjun 45100
Practice — Selecting columns
1. Print only the name and department columns.
Show one way to do it
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df[["name", "dept"]])
Output
name dept 0 Rahul HR 1 Priya Tech 2 Amit Sales 3 Kavya Tech 4 Arjun HR

loc and iloc

loc

Selects rows by their index label.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df.loc[0])
print()
print(df.loc[0:2])
Output
name Rahul dept HR salary 47764 exp 4 Name: 0, dtype: object name dept salary exp 0 Rahul HR 47764 4 1 Priya Tech 62990 7 2 Amit Sales 51200 3

iloc

Selects rows by their position. Unlike loc, the stop position is not included.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df.iloc[0:2])
print()
print(df.iloc[-1])
Output
name dept salary exp 0 Rahul HR 47764 4 1 Priya Tech 62990 7 name Arjun dept HR salary 45100 exp 2 Name: 4, dtype: object

Rows and columns

Give the rows first, then the columns.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df.loc[0:2, ["name", "salary"]])
print()
print(df.iloc[0:2, 0:2])
Output
name salary 0 Rahul 47764 1 Priya 62990 2 Amit 51200 name dept 0 Rahul HR 1 Priya Tech

at

Reads one value, given the row label and the column name.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df.at[0, "name"])
print(df.at[3, "salary"])
Output
Rahul 58300

iat

The same as at, but both the row and the column are given as numbers.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df.iat[0, 0])
print(df.iat[3, 2])
Output
Rahul 58300
Practice — loc and iloc
1. Print the first two rows using iloc, and the salary of the row labelled 2 using at.
Show one way to do it
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df.iloc[0:2])
print(df.at[2, "salary"])
Output
name dept salary exp 0 Rahul HR 47764 4 1 Priya Tech 62990 7 51200

Filtering rows

A condition

Comparing a column to a value returns True or False for every row.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df["salary"] > 50000)
Output
0 False 1 True 2 True 3 True 4 False Name: salary, dtype: bool

Filtering with a condition

Putting the condition inside the brackets keeps only the rows where it was True.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df[df["salary"] > 50000])
Output
name dept salary exp 1 Priya Tech 62990 7 2 Amit Sales 51200 3 3 Kavya Tech 58300 6

Two conditions

Use & for and, | for or. Each condition must be inside its own brackets.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df[(df["dept"] == "Tech") & (df["salary"] > 55000)])
print()
print(df[(df["dept"] == "HR") | (df["exp"] > 5)])
Output
name dept salary exp 1 Priya Tech 62990 7 3 Kavya Tech 58300 6 name dept salary exp 0 Rahul HR 47764 4 1 Priya Tech 62990 7 3 Kavya Tech 58300 6 4 Arjun HR 45100 2

and cannot be used

The word and expects one True or False, not a whole column of them.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df[(df["dept"] == "Tech") and (df["salary"] > 55000)])
Output
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

Counting matches

A condition can be summed, because True counts as 1.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print((df["salary"] > 50000).sum())
print(len(df[df["salary"] > 50000]))
Output
3 3
Practice — Filtering rows
1. Print everyone earning more than 50,000, and count how many that is.
Show one way to do it
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df[df["salary"] > 50000])
print((df["salary"] > 50000).sum())
Output
name dept salary exp 1 Priya Tech 62990 7 2 Amit Sales 51200 3 3 Kavya Tech 58300 6 3
2. Print everyone in Tech with more than five years of experience.
Show one way to do it
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df[(df["dept"] == "Tech") & (df["exp"] > 5)])
Output
name dept salary exp 1 Priya Tech 62990 7 3 Kavya Tech 58300 6

Sorting

sort_values()

Orders the rows by a column. Smallest first unless told otherwise.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df.sort_values("salary"))
Output
name dept salary exp 4 Arjun HR 45100 2 0 Rahul HR 47764 4 2 Amit Sales 51200 3 3 Kavya Tech 58300 6 1 Priya Tech 62990 7

ascending=False

Reverses the order, largest first.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df.sort_values("salary", ascending=False))
Output
name dept salary exp 1 Priya Tech 62990 7 3 Kavya Tech 58300 6 2 Amit Sales 51200 3 0 Rahul HR 47764 4 4 Arjun HR 45100 2

Several columns

Pass a list. The second column breaks ties in the first.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df.sort_values(["dept", "salary"]))
Output
name dept salary exp 4 Arjun HR 45100 2 0 Rahul HR 47764 4 2 Amit Sales 51200 3 3 Kavya Tech 58300 6 1 Priya Tech 62990 7

Sorting returns a new table

Sorting returns a new table. Assign it if the order is to be kept.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

df.sort_values("salary")
print(df["salary"].tolist())

df = df.sort_values("salary")
print(df["salary"].tolist())
Output
[47764, 62990, 51200, 58300, 45100] [45100, 47764, 51200, 58300, 62990]
Practice — Sorting
1. Sort the table by salary, highest first, and print the top two names.
Show one way to do it
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df.sort_values("salary", ascending=False)["name"].head(2).tolist())
Output
['Priya', 'Kavya']
2. Sort by department, and within each department by salary.
Show one way to do it
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df.sort_values(["dept", "salary"]))
Output
name dept salary exp 4 Arjun HR 45100 2 0 Rahul HR 47764 4 2 Amit Sales 51200 3 3 Kavya Tech 58300 6 1 Priya Tech 62990 7

Counting values

value_counts()

How many times each value appears in a column, most frequent first.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df["dept"].value_counts())
Output
dept HR 2 Tech 2 Sales 1 Name: count, dtype: int64

unique() and nunique()

The distinct values in a column, and how many there are.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df["dept"].unique())
print(df["dept"].nunique())
Output
['HR' 'Tech' 'Sales'] 3

Column statistics

The same summaries as NumPy, applied to one column.

Code
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df["salary"].sum())
print(round(df["salary"].mean(), 2))
print(df["salary"].min(), df["salary"].max())
print(df["salary"].median())
Output
265354 53070.8 45100 62990 51200.0
Practice — Counting values
1. Print how many people are in each department, and the average salary of the table.
Show one way to do it
import pandas as pd
df = pd.DataFrame({
    "name":   ["Rahul", "Priya", "Amit", "Kavya", "Arjun"],
    "dept":   ["HR", "Tech", "Sales", "Tech", "HR"],
    "salary": [47764, 62990, 51200, 58300, 45100],
    "exp":    [4, 7, 3, 6, 2]
})

print(df["dept"].value_counts())
print(round(df["salary"].mean(), 2))
Output
dept HR 2 Tech 2 Sales 1 Name: count, dtype: int64 53070.8