Lecture 1 / 16
Lecture 01 Β· Basics

Introduction & Setup

What is Python?

Python is a high-level, interpreted, dynamically-typed programming language known for its readability and simplicity. It was created by Guido van Rossum and officially released in 1991. Python was designed with one major goal in mind: making programming easier to read, write, and understand.

Unlike many older programming languages that require complex syntax, Python uses clean and straightforward code that closely resembles the English language. This makes it one of the best programming languages for beginners while remaining powerful enough for professionals working on enterprise applications.

Today, Python is one of the most popular programming languages in the world. It is used by students, software engineers, scientists, researchers, cybersecurity experts, game developers, automation engineers, and companies such as Google, Netflix, NASA, Microsoft, Dropbox, Spotify, and Instagram.

Key Features of Python
  • Readable Syntax: Python code is clean and resembles normal English, making programs easier to understand.
  • Interpreted: Python executes code line by line instead of compiling the entire program first, making testing and debugging much faster.
  • Dynamically Typed: You don't need to declare variable data types manually. Python automatically determines the appropriate type during execution.
  • Multi-paradigm: Supports Procedural Programming, Object-Oriented Programming (OOP), and Functional Programming.
  • Cross Platform: Python programs can run on Windows, Linux, and macOS with little or no modification.
  • Massive Ecosystem: Python has thousands of free libraries that help developers build websites, AI applications, desktop software, games, automation scripts, APIs, and scientific software.
  • Large Community: Millions of developers contribute tutorials, libraries, and solutions, making it easy to find help whenever you encounter a problem.

Why Learn Python?

Python is often recommended as the first programming language because it allows beginners to focus on learning programming concepts rather than complicated syntax. Once you understand Python, learning other programming languages becomes much easier.

Another reason Python is so popular is its versatility. Instead of learning different languages for different tasks, Python can be used across many fields of software development.

Common Uses of Python
  • Web Development
  • Artificial Intelligence (AI)
  • Machine Learning
  • Data Science and Data Analysis
  • Automation and Scripting
  • Cybersecurity Tools
  • Desktop Applications
  • Game Development
  • Internet of Things (IoT)
  • Cloud Computing

How Python Works

Python is called an interpreted language because it uses an interpreter to execute your code. When you run a Python program, the interpreter reads your program one line at a time, converts it into instructions the computer understands, and executes those instructions immediately.

This process makes development much faster because you don't have to compile the entire project every time you make a small change.

Python Execution Process
  • You write Python code inside a .py file.
  • The Python Interpreter reads your code.
  • Python checks for syntax errors.
  • If no errors are found, the program executes from top to bottom.
  • The results are displayed in the terminal or command prompt.

Setting Up the Environment

Before writing Python programs, you need to install Python on your computer. The official installer can be downloaded from python.org.

During installation, make sure to enable the option that says "Add Python to PATH". This allows you to run Python from any terminal or command prompt without needing to specify its installation location manually.

Once installation is complete, open your Command Prompt (Windows) or Terminal (Linux/macOS) and type:

Terminal
python --version

If Python is installed correctly, you'll see the installed version displayed, for example:

Output
Python 3.13.0

If the python command doesn't work, try:

Terminal
python3 --version

Choosing a Code Editor

You can write Python programs using any text editor, but using a proper code editor makes development much easier. Modern editors provide syntax highlighting, error detection, auto-completion, and debugging tools.

Popular Python Editors
  • Visual Studio Code (VS Code)
  • PyCharm
  • Sublime Text
  • Notepad++
  • IDLE (Included with Python)

Writing Your First Program

Traditionally, the first program every programmer writes is called Hello, World!. Although it is very simple, it teaches you how to create a Python file and execute your first program.

Create a new file named hello.py and type the following code:

hello.py
print("Hello, World!")

Save the file and open your terminal. Navigate to the folder where the file is saved, then run:

Terminal
python hello.py

The output should be:

Output
Hello, World!

Understanding the print() Function

The print() function is one of the most frequently used functions in Python. It displays information on the screen so users can see messages, numbers, variables, or the results of calculations.

Everything placed inside the parentheses of the print() function is displayed in the console.

example.py
print("Welcome to Python!")
print(100)
print(25 + 15)

The output will be:

Output
Welcome to Python!
100
40
Beginner Tips
  • Save every Python program with the .py extension.
  • Python is case-sensitive. For example, Print() is different from print().
  • Read error messages carefullyβ€”they often tell you exactly what went wrong.
  • Practice writing small programs regularly to improve your programming skills.
  • Experiment with the code by changing values and observing the output.
🎯 Exercise 1

Complete the following tasks:

  • Install Python on your computer.
  • Verify the installation using python --version.
  • Create a file named hello.py.
  • Write the "Hello, World!" program.
  • Run the program from your terminal or command prompt.
  • Modify the program to display your own name.
  • Finally, run the following command to verify your installation:
Terminal
python -c "print('Python is set up successfully!')"
Lecture 02 Β· Basics

Variables & Data Types

Variables and Dynamic Typing

A variable is a named location in memory used to store data that can be accessed and modified throughout a program. Variables allow programmers to save information such as numbers, text, or logical values so they can be reused whenever needed.

Unlike some programming languages, Python does not require you to declare the data type of a variable before using it. Instead, Python automatically creates the variable when you assign a value using the assignment operator (=).

This feature is known as dynamic typing. Python determines the variable's data type automatically based on the value assigned to it. If the value changes, the variable's data type can also change.

How Variables Work
  • A variable stores information in memory.
  • The variable name acts as a label for accessing that information.
  • Variables can be updated as many times as needed.
  • Python automatically determines the appropriate data type.
  • No special keywords are required to create variables.

For example:

variables.py
message = "Hello"
print(message)

message = "Welcome to Python"
print(message)

Notice that the variable message is reused with a different value. This is completely normal in Python.

Dynamic Typing Example

Because Python is dynamically typed, a variable can even change from one data type to another during program execution.

dynamic.py
value = 100
print(type(value))

value = "One Hundred"
print(type(value))

value = True
print(type(value))

Although Python allows this flexibility, constantly changing a variable's data type can make programs difficult to understand. It is considered good practice to keep variables representing the same kind of information.

Variable Naming Rules

Python has several rules that every variable name must follow.

Rules for Naming Variables
  • Variable names can contain letters, numbers, and underscores (_).
  • A variable name cannot begin with a number.
  • Variable names are case-sensitive.
  • Spaces are not allowed inside variable names.
  • Avoid using Python keywords such as if, for, or while as variable names.

Examples of valid variable names:

valid_names.py
student_name = "Alice"
age = 18
total_marks = 450
price2 = 199.99
_is_logged_in = True

Examples of invalid variable names:

invalid_names.py
2price = 50          # Starts with a number
student name = "Bob" # Contains a space
for = 10             # Python keyword

Variable Naming Conventions

Although Python allows many naming styles, professional Python developers generally follow the snake_case naming convention.

Recommended Naming Style
  • student_name βœ”οΈ
  • total_marks βœ”οΈ
  • account_balance βœ”οΈ
  • StudentName ❌ (Usually reserved for classes)
  • studentName ❌ (Less common in Python)

Standard Data Types

Every value stored in Python belongs to a particular data type. The data type determines what kind of information the value represents and what operations can be performed on it.

The four most common built-in data types are:

  • Integers (int): Whole numbers without decimal places, such as 5, 100, and -25.
  • Floating Point Numbers (float): Numbers containing decimal points, such as 3.14, 99.95, and -0.5.
  • Strings (str): Text enclosed inside single or double quotation marks.
  • Booleans (bool): Logical values that can only be True or False.
Examples of Data Types
  • int: 1, 20, -100
  • float: 5.5, 100.01, -8.2
  • str: "Python", "Hello World"
  • bool: True, False

Creating Variables

Creating variables in Python is simple. Assign a value using the assignment operator (=).

datatypes.py
age = 25              # Integer
price = 19.99         # Float
name = "CodeTutor"    # String
is_active = True      # Boolean

print(type(age))      # Output: <class 'int'>
print(type(price))    # Output: <class 'float'>
print(type(name))     # Output: <class 'str'>
print(type(is_active))# Output: <class 'bool'>

The type() Function

The type() function is used to determine the data type of any value or variable. This function is especially useful while learning Python because it allows you to verify exactly what type of data Python has assigned.

type_function.py
x = 50
y = 3.14
z = "Python"

print(type(x))
print(type(y))
print(type(z))

Multiple Variable Assignment

Python also allows multiple variables to be assigned in a single line.

multiple_assignment.py
x, y, z = 10, 20, 30

print(x)
print(y)
print(z)

You can also assign the same value to multiple variables.

same_value.py
a = b = c = 100

print(a)
print(b)
print(c)

Best Practices

Good Programming Habits
  • Use meaningful variable names.
  • Avoid very short names unless used for simple loops.
  • Use snake_case for multi-word variable names.
  • Keep variables related to one purpose.
  • Choose names that describe the data they store.

Common Beginner Mistakes

Watch Out For
  • Using spaces in variable names.
  • Starting variable names with numbers.
  • Confusing = (assignment) with == (comparison).
  • Misspelling variable names.
  • Using reserved Python keywords as variable names.
🎯 Exercise 2

Create a Python program that performs the following tasks:

  • Create a variable for a book title.
  • Create a variable for the author's name.
  • Create a variable for the book price.
  • Create a variable for the book rating out of 5.
  • Create a variable that stores whether the book is currently in stock.
  • Print each variable.
  • Use the type() function to display the data type of every variable.
  • Change one variable to a different data type and observe how Python automatically updates its type.
Lecture 03 Β· Basics

Operators & Expressions

What are Operators?

Operators are special symbols that tell Python to perform a particular operation on one or more values. These values are called operands. Operators allow programmers to perform calculations, compare values, combine conditions, assign data to variables, and much more.

For example, in the expression 5 + 3, the + symbol is an operator, while 5 and 3 are operands. Python evaluates the expression and returns the result 8.

Operators are one of the most important building blocks of programming because nearly every program performs some type of calculation or decision using operators.

Categories of Python Operators
  • Arithmetic Operators
  • Assignment Operators
  • Comparison Operators
  • Logical Operators
  • Identity Operators
  • Membership Operators
  • Bitwise Operators (Advanced)

What are Expressions?

An expression is a combination of values, variables, operators, and function calls that Python evaluates to produce a single result.

For example:

expressions.py
x = 10
y = 5

result = x + y
print(result)

The expression x + y is evaluated first, and the result is then stored in the variable result.

Arithmetic Operators

Arithmetic operators are used with numeric values to perform common mathematical calculations. They work with integers and floating-point numbers.

Arithmetic Operators
  • + Addition
  • - Subtraction
  • * Multiplication
  • / Division (Always returns a float)
  • // Floor Division (Returns the whole-number quotient)
  • % Modulus (Returns the remainder)
  • ** Exponentiation (Raises one number to the power of another)
arithmetic.py
a = 15
b = 4

print(a + b)
print(a - b)
print(a * b)
print(a / b)
print(a // b)
print(a % b)
print(a ** b)

Output:

Output
19
11
60
3.75
3
3
50625

Understanding Each Arithmetic Operator

Addition (+) adds two numbers together.

addition.py
print(10 + 5)

Subtraction (-) subtracts one value from another.

subtraction.py
print(20 - 7)

Multiplication (*) multiplies two numbers.

multiplication.py
print(6 * 8)

Division (/) divides one number by another. The result is always a floating-point number.

division.py
print(20 / 4)
print(5 / 2)

Floor Division (//) removes the decimal portion and returns only the whole number.

floor_division.py
print(20 // 4)
print(5 // 2)

Modulus (%) returns the remainder after division.

modulus.py
print(10 % 3)
print(18 % 5)

Exponentiation (**) raises one number to the power of another.

power.py
print(2 ** 3)
print(5 ** 2)

Assignment Operators

Assignment operators are used to store values inside variables. Python also provides shorthand assignment operators that combine arithmetic with assignment.

Common Assignment Operators
  • = Assign value
  • += Add and assign
  • -= Subtract and assign
  • *= Multiply and assign
  • /= Divide and assign
  • //= Floor divide and assign
  • %= Modulus and assign
  • **= Exponentiate and assign
assignment.py
score = 50

score += 10
score *= 2

print(score)

Comparison Operators

Comparison operators compare two values and always return either True or False. They are commonly used when making decisions in a program.

Comparison Operators
  • == Equal to
  • != Not equal to
  • > Greater than
  • < Less than
  • >= Greater than or equal to
  • <= Less than or equal to
comparison.py
age = 18

print(age == 18)
print(age != 20)
print(age > 15)
print(age < 30)

Logical Operators

Logical operators combine multiple conditions together. They are mainly used with comparison operators to build more complex decision-making statements.

Logical Operators
  • and Returns True if both conditions are True.
  • or Returns True if at least one condition is True.
  • not Reverses the Boolean value.
logical.py
has_discount = True
is_member = False

print(has_discount and is_member)
print(has_discount or is_member)
print(not is_member)

Identity Operators

Identity operators compare whether two variables refer to the same object in memory.

Identity Operators
  • is Returns True if both variables reference the same object.
  • is not Returns True if they reference different objects.
identity.py
x = [1, 2]
y = x

print(x is y)
print(x is not y)

Membership Operators

Membership operators check whether a value exists inside a sequence such as a string, list, or tuple.

Membership Operators
  • in Returns True if the value exists.
  • not in Returns True if the value does not exist.
membership.py
language = "Python"

print("P" in language)
print("Java" not in language)

Operator Precedence

When an expression contains multiple operators, Python follows a specific order of operations known as operator precedence.

Order of Evaluation
  • () Parentheses
  • ** Exponentiation
  • * / // % Multiplication, Division, Floor Division, Modulus
  • + - Addition and Subtraction
  • Comparison Operators
  • not
  • and
  • or
precedence.py
result = 10 + 5 * 2
print(result)

result = (10 + 5) * 2
print(result)

Common Beginner Mistakes

Watch Out For
  • Using = instead of == for comparisons.
  • Forgetting that / always returns a float.
  • Confusing // with /.
  • Ignoring operator precedence.
  • Using logical operators with incorrect conditions.
operators.py
# Arithmetic
result = 10 // 3
remainder = 10 % 3
power = 2 ** 3

# Comparison & Logical
has_discount = True
is_member = False
can_buy = has_discount and not is_member

print(result)
print(remainder)
print(power)
print(can_buy)
🎯 Exercise 3

Complete the following tasks:

  • Create variables for the radius and the value of pi.
  • Calculate the area of a circle using the formula pi * radius ** 2.
  • Print the calculated area.
  • Determine whether the area is greater than 100 using a comparison operator.
  • Create two Boolean variables and combine them using the and, or, and not operators.
  • Experiment with parentheses to observe how operator precedence changes the result.
Lecture 04 Β· Basics

Control Flow

Conditional Statements

Conditional structures allow a program to make decisions and execute different blocks of code based on conditions. Python uses the keywords if, elif (else if), and else.

Every program needs a way to make decisions. Imagine a login system checking whether a password is correct, or a game deciding whether the player has won or lost. These are examples of decision-making, also known as control flow. Instead of executing every line of code from top to bottom, Python can choose which code to execute depending on whether a condition is True or False.

A condition is simply an expression that evaluates to either True or False. Python evaluates the condition first, and then executes the appropriate block of code.

⚠️ Python Indentation

Unlike languages like C++ or Java that use curly braces {} to define code blocks, Python relies entirely on indentation (typically 4 spaces). Incorrect indentation will cause an IndentationError.

Comparison Operators

Conditional statements usually work together with comparison operators. These operators compare two values and return either True or False.

comparison.py
age = 20

print(age == 20)   # True
print(age != 18)   # True
print(age > 18)    # True
print(age < 18)    # False
print(age >= 20)   # True
print(age <= 21)   # True

The most common comparison operators are:

  • == Equal to
  • != Not equal to
  • > Greater than
  • < Less than
  • >= Greater than or equal to
  • <= Less than or equal to

The if Statement

The if statement executes a block of code only if its condition is True. If the condition is False, Python skips that block and continues with the next statement.

if_example.py
temperature = 35

if temperature > 30:
    print("It is a hot day.")

Since the condition temperature > 30 is true, the message will be displayed.

The if...else Statement

The else block runs when the condition inside the if statement is false. It provides an alternative path for the program.

if_else.py
age = 16

if age >= 18:
    print("You are an adult.")
else:
    print("You are a minor.")

The if...elif...else Statement

Sometimes there are more than two possible outcomes. The elif keyword allows Python to check additional conditions after the first one.

control_flow.py
score = 85

if score >= 90:
    print("Grade: A")
elif score >= 80:
    print("Grade: B")  # This block runs
else:
    print("Grade: C")

Python checks each condition from top to bottom. As soon as one condition becomes True, its block executes and the remaining conditions are ignored.

Flow of Execution

The order in which Python evaluates an if-elif-else statement is:

  1. Evaluate the if condition.
  2. If it is true, execute that block and skip the rest.
  3. If it is false, evaluate the first elif.
  4. Continue checking each elif until one is true.
  5. If none of the conditions are true, execute the else block.

Logical Operators

Sometimes you need to combine multiple conditions. Python provides logical operators for this purpose.

  • and – Both conditions must be true.
  • or – At least one condition must be true.
  • not – Reverses a condition.
logical.py
age = 25
has_id = True

if age >= 18 and has_id:
    print("Access granted.")
or_example.py
is_weekend = False
is_holiday = True

if is_weekend or is_holiday:
    print("You can relax today!")
not_example.py
logged_in = False

if not logged_in:
    print("Please log in.")

Nested Conditional Statements

You can place one conditional statement inside another. This is called nesting.

nested_if.py
age = 22
citizen = True

if age >= 18:
    if citizen:
        print("Eligible to vote.")
    else:
        print("Citizenship required.")
else:
    print("Too young to vote.")

Common Mistakes

⚠️ Common Errors

Beginners often make these mistakes:

  • Using = instead of == when comparing values.
  • Forgetting to add a colon : after if, elif, or else.
  • Incorrect indentation.
  • Writing multiple else blocks for the same if statement.
  • Checking conditions in the wrong order, causing some conditions to never execute.

Real-World Applications

Conditional statements are used in almost every Python application, including:

  • Login and authentication systems.
  • ATM and banking software.
  • Games that respond to player actions.
  • Weather applications.
  • Student grading systems.
  • E-commerce websites that calculate discounts.
  • Security systems that verify permissions.

Summary

In this lesson you learned how Python controls the flow of a program using conditional statements. You learned how to use if, elif, and else, how comparison and logical operators work, how nested conditions are written, and some common mistakes to avoid. These concepts are essential because they allow programs to make intelligent decisions based on different situations.

🎯 Exercise 4

Write a program that takes a number and prints whether it is "Positive", "Negative", or "Zero". Add checking to see if it is even or odd if it is positive.

Bonus Challenges:

  1. Ask the user to enter their age and determine whether they are a child, teenager, adult, or senior.
  2. Create a simple grading system that prints A, B, C, D, or F based on a student's score.
  3. Write a program that asks for a username and password and displays whether login is successful.
  4. Ask the user to enter three numbers and print the largest number.
  5. Create a calculator that asks the user to choose an operation (+, -, *, /) and performs the selected calculation.
Lecture 05 Β· Basics

Loops & Iteration

Introduction to Loops

Loops are one of the most important programming concepts in Python. They allow you to execute the same block of code multiple times without writing it repeatedly. Instead of copying and pasting the same code over and over, you can place it inside a loop and let Python repeat it automatically.

Loops are useful whenever you need to process collections of data, repeat calculations, validate user input, search through information, or automate repetitive tasks. Nearly every real-world Python program uses loops in some form.

Why Use Loops?
  • Reduce duplicate code.
  • Process large amounts of data efficiently.
  • Repeat actions automatically.
  • Iterate through lists, strings, tuples, dictionaries, and other collections.
  • Create cleaner, shorter, and easier-to-maintain programs.

What is Iteration?

Iteration means repeating a process multiple times. Each time a loop executes its body, it completes one iteration. The loop continues running until its stopping condition is met or until it reaches the end of the sequence it is iterating over.

For example, if a loop prints numbers from 1 to 5, it performs five separate iterations.

While Loops

A while loop repeatedly executes a block of code as long as a specified condition evaluates to True. Before each iteration, Python checks the condition. If it remains true, the loop continues. Once the condition becomes false, the loop stops.

A while loop is useful when you do not know exactly how many times a task should repeat.

Syntax of a While Loop
  • Python checks the condition.
  • If the condition is True, the loop body executes.
  • After execution, Python checks the condition again.
  • The process repeats until the condition becomes False.
while_loop.py
count = 1

while count <= 5:
    print(count)
    count += 1

Output:

Output
1
2
3
4
5

Notice that the variable count increases during each iteration. Eventually the condition count <= 5 becomes false, causing the loop to terminate.

Infinite Loops

An infinite loop occurs when the loop condition never becomes false. This causes the loop to run forever until the program is manually stopped.

infinite.py
while True:
    print("This loop never ends!")

Infinite loops are sometimes useful in applications such as games, servers, or continuously running programs, but they should usually contain a break statement to provide a way to exit.

For Loops

A for loop is used to iterate over a sequence such as a string, list, tuple, dictionary, set, or the values produced by the range() function.

Unlike a while loop, a for loop automatically moves to the next item in the sequence until every element has been processed.

for_loop.py
fruits = ["Apple", "Banana", "Orange"]

for fruit in fruits:
    print(fruit)

The range() Function

The range() function generates a sequence of numbers and is commonly used with for loops when you want to repeat a task a specific number of times.

Different Ways to Use range()
  • range(stop)
  • range(start, stop)
  • range(start, stop, step)
range_examples.py
for i in range(5):
    print(i)

print()

for i in range(1, 6):
    print(i)

print()

for i in range(2, 11, 2):
    print(i)

Output:

Output
0
1
2
3
4

1
2
3
4
5

2
4
6
8
10

Looping Through Strings

Strings are sequences of characters, so they can also be iterated one character at a time.

string_loop.py
word = "Python"

for letter in word:
    print(letter)

Nested Loops

A nested loop is simply a loop inside another loop. Nested loops are useful when working with tables, grids, matrices, or when comparing multiple values.

nested_loops.py
for i in range(1, 4):
    for j in range(1, 4):
        print(i, j)

Loop Control Statements

Python provides several statements that change the normal behavior of loops.

Loop Control Statements
  • break – Immediately terminates the loop.
  • continue – Skips the current iteration and continues with the next one.
  • pass – Does nothing and acts as a placeholder.

The break Statement

The break statement exits the loop immediately, even if there are more iterations remaining.

break.py
for number in range(1, 10):
    if number == 6:
        break

    print(number)

The continue Statement

The continue statement skips the current iteration and moves directly to the next one.

continue.py
for number in range(1, 6):
    if number == 3:
        continue

    print(number)

The pass Statement

The pass statement is used when Python expects a block of code but you do not want to write any functionality yet. It is commonly used while developing programs.

pass.py
for i in range(5):
    pass

Complete Example

loops.py
# For loop with range
for i in range(1, 6):
    if i == 3:
        continue
    print(i)

print()

# While loop with break
count = 0

while True:
    print("Count:", count)
    count += 1

    if count >= 3:
        break

Real-World Uses of Loops

Where Loops Are Used
  • Reading files line by line.
  • Processing lists of students or products.
  • Searching for specific information.
  • Generating reports.
  • Creating games and animations.
  • Automating repetitive computer tasks.
  • Validating user input.
  • Machine learning and data analysis.

Common Beginner Mistakes

Watch Out For
  • Forgetting to update the loop variable in a while loop.
  • Creating accidental infinite loops.
  • Incorrect indentation inside loops.
  • Using break when continue is intended.
  • Using the wrong range values.
🎯 Exercise 5

Complete the following programming exercises:

  • Print the numbers from 1 to 20 using a for loop.
  • Print only the even numbers between 1 and 20.
  • Use a while loop to count backwards from 10 to 1.
  • Create a multiplication table for the number 7.
  • Print every character of your name using a for loop.
  • Write a program that prints all prime numbers between 2 and 30 using nested loops and the break statement.
  • Modify the prime number program so it counts how many prime numbers were found.
Lecture 06 Β· Basics

Functions & Scope

Defining and Calling Functions

Functions are blocks of organized, reusable code used to perform a single related action. In Python, functions are defined using the def keyword, followed by the function name and parentheses containing parameters.

Functions help programmers avoid writing the same code repeatedly. Instead of copying and pasting code multiple times, you can place it inside a function and call it whenever it is needed. This makes programs shorter, easier to read, easier to debug, and much easier to maintain.

Think of a function as a small machine. You provide it with some input (arguments), it performs a task, and it may produce an output (a return value). Every function should ideally perform one specific job.

simple_function.py
def greet():
    print("Hello, World!")

greet()

When Python reaches greet(), it jumps to the function, executes its code, and then returns to the next line after the function call.

Function Naming

Function names should clearly describe what the function does. According to Python's naming convention (PEP 8), function names should be written in lowercase with words separated by underscores.

naming.py
def calculate_area():
    pass

def print_report():
    pass

def send_email():
    pass

Arguments and Parameters

A parameter is a variable listed in a function definition, while an argument is the actual value passed to the function when it is called.

parameters.py
def greet(name):
    print("Hello", name)

greet("Alice")
greet("John")

In this example, name is the parameter, while "Alice" and "John" are arguments.

Arguments and Return Values

Functions can accept arguments and return values using the return statement. If no return value is specified, the function returns None. Python supports default arguments, keyword arguments, and arbitrary arguments (*args and **kwargs).

The return statement sends a value back to the part of the program that called the function. Once a return statement executes, the function immediately stops running.

return_example.py
def square(number):
    return number * number

result = square(6)
print(result)

Default Arguments

Default arguments allow a function to use a predefined value if no argument is supplied by the caller.

default_arguments.py
def greet(name, message="Welcome"):
    print(f"{message}, {name}")

greet("Alice")
greet("Bob", "Good Morning")

If no second argument is provided, Python automatically uses the default value.

Keyword Arguments

Python allows arguments to be passed using their parameter names. These are called keyword arguments.

keyword_arguments.py
def introduce(name, age):
    print(name, age)

introduce(age=20, name="Alice")

Keyword arguments improve readability and allow arguments to be supplied in any order.

Arbitrary Arguments

Sometimes you do not know how many arguments will be passed. Python provides *args and **kwargs for these situations.

args.py
def total(*numbers):
    print(sum(numbers))

total(10, 20)
total(10, 20, 30, 40)
kwargs.py
def display(**person):
    print(person["name"])
    print(person["age"])

display(name="Alice", age=25)

Variable Scope

Variables defined inside a function are in the local scope and cannot be accessed outside. Variables defined outside are in the global scope. Use the global keyword to modify a global variable inside a function.

Scope determines where a variable can be accessed in your program. Understanding scope helps prevent unexpected errors and makes programs easier to understand.

Local Variables

Variables created inside a function exist only while that function is running.

local_scope.py
def example():
    message = "Inside function"
    print(message)

example()

The variable message cannot be accessed outside the function because it belongs to the local scope.

Global Variables

Variables created outside every function belong to the global scope. They can usually be accessed from anywhere in the program.

global_scope.py
language = "Python"

def show_language():
    print(language)

show_language()

The global Keyword

Normally, assigning a value to a variable inside a function creates a new local variable. To modify a global variable, you must use the global keyword.

functions.py
def greet(name, message="Welcome"):
    return f"Hello {name}, {message}!"

# Call function
greeting = greet("Alice")
print(greeting)  # Output: Hello Alice, Welcome!

# Variable Scope
total = 0  # Global variable

def add_to_total(amount):
    global total
    total += amount

add_to_total(25)
print(total)

Why Functions Are Important

Functions provide several advantages when writing software:

  • Reduce duplicated code.
  • Make programs easier to read.
  • Allow code to be reused throughout a project.
  • Make debugging easier because each function performs one task.
  • Help organize large programs into smaller, manageable sections.
  • Allow multiple programmers to work on different parts of the same project.

Common Mistakes

⚠️ Common Errors
  • Forgetting the parentheses when calling a function.
  • Using the wrong number of arguments.
  • Confusing parameters with arguments.
  • Trying to use local variables outside their function.
  • Forgetting to use return when a value should be sent back.
  • Modifying global variables without the global keyword.

Real-World Applications

Functions are used everywhere in software development, including:

  • User authentication systems.
  • Mathematical calculations.
  • Database operations.
  • Processing user input.
  • File handling.
  • Web applications.
  • Game development.
  • Machine learning projects.

Summary

Functions are one of the most powerful features in Python. They allow programmers to organize code into reusable blocks that perform specific tasks. In this lesson you learned how to define functions, pass arguments, return values, use default and keyword arguments, work with *args and **kwargs, understand local and global scope, and avoid common mistakes. Mastering functions is an essential step toward writing clean, efficient, and professional Python programs.

🎯 Exercise 6

Create a function called calculate_tax that accepts a subtotal price and an optional tax rate (defaulting to 0.08). The function should return the total price including tax.

Bonus Challenges:

  1. Create a function that converts Celsius to Fahrenheit.
  2. Write a function that returns the largest of three numbers.
  3. Create a function that counts the number of vowels in a string.
  4. Write a function using *args that calculates the average of any number of values.
  5. Create a simple calculator using separate functions for addition, subtraction, multiplication, and division.
Lecture 07 Β· Data Structures

Lists & Tuples

Lists (Mutable Sequences)

A list is a ordered, mutable collection of items. Lists can contain items of different data types, and allow duplicate values. Items are indexable starting from 0, and support negative indexing (counting from the end).

Tuples (Immutable Sequences)

A tuple is similar to a list, but it is **immutable** (cannot be modified after creation). Tuples are defined using parentheses () and are useful for read-only data structures or returning multiple values from a function.

lists_tuples.py
# List operations
fruits = ["apple", "banana", "cherry"]
fruits.append("orange")
fruits[0] = "blueberry"  # Allowed (mutable)
print(fruits[1:3])       # Slicing: ['banana', 'cherry']

# Tuple operations
coordinates = (10.0, 20.0)
# coordinates[0] = 15.0  # TypeError (immutable)
🎯 Exercise 7

Given the list numbers = [12, 45, 2, 41, 31, 10, 8, 6, 4], write a script to find the maximum value, reverse the list, append the number 99, and print the resulting slice of the first three items.

Lecture 08 Β· Data Structures

Dictionaries & Sets

Dictionaries (Key-Value Pairs)

A dictionary is an unordered, mutable collection of key-value pairs. Keys must be unique and immutable (such as strings, numbers, or tuples), while values can be of any data type. Dictionaries are optimized for retrieving values when you know the key.

Dictionaries are one of the most useful data structures in Python. Instead of storing values by position like a list, dictionaries store values using keys. Each key acts like a label that points to its corresponding value, making data easy to organize and retrieve.

Think of a dictionary as a real-world dictionary. You search for a word (the key), and the dictionary gives you its definition (the value). Python dictionaries work in the same way.

Creating Dictionaries

Dictionaries are created using curly braces {}, where each key is separated from its value using a colon (:).

create_dictionary.py
student = {
    "name": "Alice",
    "age": 20,
    "course": "Computer Science"
}

print(student)

Accessing Dictionary Values

You can access values by using their keys inside square brackets or by using the safer get() method.

access_dictionary.py
student = {
    "name": "Alice",
    "age": 20
}

print(student["name"])
print(student.get("age"))

If a key does not exist, get() returns None (or a default value if provided) instead of raising an error.

get_default.py
student = {
    "name": "Alice"
}

print(student.get("grade", "Not Available"))

Adding and Updating Items

Dictionaries are mutable, meaning you can easily add new key-value pairs or update existing values.

update_dictionary.py
student = {
    "name": "Alice",
    "age": 20
}

student["age"] = 21
student["grade"] = "A"

print(student)

Removing Items

Dictionary items can be removed using pop(), del, or clear().

remove_dictionary.py
student = {
    "name": "Alice",
    "age": 20,
    "grade": "A"
}

student.pop("grade")
print(student)

Looping Through Dictionaries

You can loop through dictionary keys, values, or both using a for loop.

dictionary_loop.py
student = {
    "name": "Alice",
    "age": 20,
    "grade": "A"
}

for key, value in student.items():
    print(key, value)

Common Dictionary Methods

  • get() – Returns the value for a key.
  • keys() – Returns all dictionary keys.
  • values() – Returns all values.
  • items() – Returns key-value pairs.
  • pop() – Removes a specified item.
  • update() – Updates multiple items.
  • clear() – Removes all items.

Sets (Unique Collections)

A set is an unordered collection of unique elements. Sets are written with curly braces {} and are useful for removing duplicate values from sequences and performing mathematical set operations (union, intersection, difference).

Unlike lists, sets do not allow duplicate values. If duplicate elements are added, Python automatically keeps only one copy of each value.

create_set.py
numbers = {1, 2, 2, 3, 4, 4, 5}

print(numbers)

Adding and Removing Set Elements

Sets are mutable, allowing elements to be added or removed after creation.

set_methods.py
colors = {"red", "blue"}

colors.add("green")
colors.remove("red")

print(colors)

Set Operations

Sets support several mathematical operations that are useful when comparing collections.

  • Union combines all unique elements.
  • Intersection returns common elements.
  • Difference returns elements that exist in one set but not the other.
  • Symmetric Difference returns elements that are unique to each set.
set_operations.py
a = {1, 2, 3}
b = {3, 4, 5}

print(a.union(b))
print(a.intersection(b))
print(a.difference(b))
print(a.symmetric_difference(b))

Checking Membership

You can quickly check whether an item exists in a dictionary or set using the in keyword.

membership.py
student = {
    "name": "Alice",
    "grade": "A"
}

if "grade" in student:
    print("Grade found.")

colors = {"red", "green", "blue"}

if "green" in colors:
    print("Green exists.")

Dictionary vs Set

Dictionary Set
Stores key-value pairs. Stores unique values only.
Uses keys to access values. Has no keys or indexes.
Mutable. Mutable.
Duplicate keys are not allowed. Duplicate values are automatically removed.
dicts_sets.py
# Dictionary operations
student = {"name": "Bob", "grade": "A", "age": 20}

student["age"] = 21
student["major"] = "CS"

print(student.get("grade"))

# Set operations
a = {1, 2, 3, 3}
b = {3, 4, 5}

print(a.union(b))
print(a.intersection(b))
print(a.difference(b))
print(a.symmetric_difference(b))

Real-World Applications

Dictionaries and sets are used in many software applications:

  • Student management systems.
  • User account information.
  • Online shopping carts.
  • Phone contact applications.
  • Word frequency counters.
  • Removing duplicate records from datasets.
  • Database caching and fast lookups.
  • Permission and role management systems.

Common Mistakes

⚠️ Common Errors
  • Trying to access a dictionary key that does not exist.
  • Assuming dictionaries are accessed using numeric indexes like lists.
  • Expecting sets to keep duplicate values.
  • Trying to access set elements using indexes.
  • Using mutable objects such as lists as dictionary keys.
  • Forgetting that dictionaries require unique keys.

Summary

Dictionaries and sets are powerful built-in Python data structures. Dictionaries organize information using key-value pairs, making data retrieval fast and efficient. Sets store only unique elements and provide useful mathematical operations such as union, intersection, and difference. Mastering these data structures will help you write cleaner, faster, and more efficient Python programs.

🎯 Exercise 8

Create a dictionary representing a simple store inventory with product names as keys and prices as values. Write code to check if "milk" is in the inventory. If it is, update its price; if not, add it with a price of 2.50.

Bonus Challenges:

  1. Create a phone book using a dictionary.
  2. Count how many times each word appears in a sentence using a dictionary.
  3. Remove duplicate numbers from a list using a set.
  4. Find the common elements between two lists by converting them into sets.
  5. Create a student record system where each student has a name, age, and grade stored in a dictionary.
Lecture 09 Β· Data Structures

String Processing

String Slicing and Formatting

Strings are one of the most commonly used data types in Python. A string is a sequence of characters enclosed in either single quotes (' ') or double quotes (" "). Strings are used to store and manipulate text such as names, sentences, passwords, file names, and user input.

Python strings are immutable, which means that once a string has been created, its characters cannot be changed directly. If you perform an operation that appears to modify a string, Python actually creates a new string instead of changing the original one.

Since strings are sequences, each character has an index. The first character starts at index 0, the second at 1, and so on. Python also supports negative indexing, where -1 represents the last character, -2 represents the second last character, and so forth.

One of Python's most powerful features is string slicing. Slicing allows you to extract a portion of a string using the syntax string[start:end:step].

  • start – The index where slicing begins (inclusive).
  • end – The index where slicing stops (exclusive).
  • step – Determines how many characters to skip between each selection.

Examples of slicing:

  • text[0:5] β†’ Returns characters from index 0 to 4.
  • text[:5] β†’ Starts from the beginning and stops before index 5.
  • text[3:] β†’ Returns everything from index 3 to the end.
  • text[-4:] β†’ Returns the last four characters.
  • text[::-1] β†’ Returns the string in reverse order.

Python also provides several ways to insert variables into strings. The recommended and most modern method is using f-strings, introduced in Python 3.6. An f-string begins with the letter f before the quotation marks and allows variables or expressions to be embedded directly inside curly braces ({ }).

F-strings are easier to read, faster than older formatting methods, and are widely used in professional Python applications for displaying messages, reports, and formatted output.

Common String Methods

Python provides many built-in methods that make working with strings simple and efficient. These methods return new strings rather than modifying the original string because strings are immutable.

  • strip(): Removes whitespace from both the beginning and end of a string. It is commonly used to clean user input.
  • lower(): Converts every letter in a string to lowercase. Useful for case-insensitive comparisons.
  • upper(): Converts every character to uppercase.
  • split(separator): Splits a string into a list using the specified separator. If no separator is given, spaces are used automatically.
  • join(iterable): Joins all items from a list or other iterable into one string using the specified separator.
  • replace(old, new): Replaces every occurrence of one substring with another.
  • startswith(): Checks whether a string begins with a specified sequence of characters.
  • endswith(): Checks whether a string ends with a specified sequence.
  • find(): Returns the index of the first occurrence of a substring. If it is not found, it returns -1.
  • count(): Counts how many times a substring appears inside a string.
  • isalpha(): Returns True if all characters are alphabetic.
  • isdigit(): Returns True if all characters are numeric digits.
  • isalnum(): Returns True if all characters are either letters or numbers.

These methods are extremely useful when validating user input, processing files, formatting text, searching for keywords, and cleaning data before analysis.

strings.py
# Original string
msg = "  Python Coding  "

# Remove extra spaces
clean_msg = msg.strip()

# Convert to uppercase
clean_msg = clean_msg.upper()

print(clean_msg)
# Output: PYTHON CODING

# String slicing
text = "Programming"

print(text[0:7])     # Program
print(text[3:])      # gramming
print(text[-4:])     # ming
print(text[::-1])    # gnimmargorP

# f-strings
name = "Alice"
version = 3.12

sentence = f"Hello {name}, you are using Python {version}."
print(sentence)

# Split a sentence into words
words = clean_msg.split()
print(words)
# ['PYTHON', 'CODING']

# Join words using a separator
rejoined = "-".join(words)
print(rejoined)
# PYTHON-CODING

# Replace text
message = "I like Java."
updated = message.replace("Java", "Python")
print(updated)

# Find text
position = updated.find("Python")
print(position)

# Count characters
print(updated.count("o"))

# Check the beginning and end
print(updated.startswith("I"))
print(updated.endswith("."))
🎯 Exercise 9

Write a program that asks the user to enter a sentence.

Your program should perform the following tasks:

  • Count and display the total number of spaces.
  • Count the total number of words in the sentence.
  • Convert the sentence to uppercase.
  • Replace every vowel (a, e, i, o, u) with an asterisk (*).
  • Display the reversed version of the sentence using string slicing.
  • Print the final processed sentence.

Challenge: Modify your program so that it also counts how many vowels were replaced and displays that number to the user.

Lecture 10 Β· Advanced Concepts

File Handling

Reading and Writing Files

Python makes it easy to read from and write to external files. The basic built-in function to open a file is open(filename, mode). Common modes include "r" for reading, "w" for writing (overwriting), and "a" for appending.

File handling allows programs to store information permanently. Unlike variables, whose values disappear when a program ends, data saved in a file remains available the next time the program is run. File handling is essential for creating applications that save user information, settings, reports, logs, and databases.

Python provides powerful built-in tools for working with files, making it simple to create, read, update, and delete data stored on your computer.

πŸ’‘ Use Context Managers

Always open files using the with statement (Context Manager). This ensures that the file is automatically closed when execution leaves the block, preventing resource leaks even if exceptions occur.

Understanding File Modes

The second argument passed to open() specifies how the file should be used. Choosing the correct mode is important because each mode behaves differently.

Mode Description
r Read a file. The file must already exist.
w Write to a file. Creates a new file or overwrites an existing one.
a Append data to the end of a file without deleting existing content.
x Create a new file. Generates an error if the file already exists.
rb Read a binary file such as an image or video.
wb Write binary data to a file.

Writing to a File

The write() method writes text into a file. If the file is opened in "w" mode, any existing content will be replaced.

write_file.py
with open("message.txt", "w") as file:
    file.write("Welcome to Python!")
    file.write("\nLearning file handling.")

Reading an Entire File

The read() method reads all the contents of a file and returns it as a string.

read_file.py
with open("message.txt", "r") as file:
    content = file.read()

print(content)

Reading One Line at a Time

Sometimes files are very large. Instead of reading everything at once, you can read one line at a time using readline().

readline.py
with open("message.txt", "r") as file:
    print(file.readline())
    print(file.readline())

Reading Files with a Loop

A for loop provides an efficient way to process files line by line.

loop_file.py
with open("message.txt", "r") as file:
    for line in file:
        print(line.strip())

The strip() method removes unnecessary whitespace and newline characters from each line.

Appending to a File

Using append mode ("a") adds new data to the end of the file without removing the existing content.

append_file.py
with open("message.txt", "a") as file:
    file.write("\nThis line was appended.")

Working with File Paths

A file path tells Python where a file is located. If only the filename is provided, Python looks for the file in the current working directory.

paths.py
with open("documents/report.txt", "r") as file:
    print(file.read())

Checking if a File Exists

Before opening a file, it is often useful to check whether it exists to avoid runtime errors.

file_exists.py
import os

if os.path.exists("message.txt"):
    print("File exists.")
else:
    print("File not found.")

Handling File Errors

If Python cannot find a file, it raises a FileNotFoundError. You can handle this error using a try...except block.

file_errors.py
try:
    with open("missing.txt", "r") as file:
        print(file.read())
except FileNotFoundError:
    print("The file could not be found.")

Working with Binary Files

Not all files contain text. Images, videos, PDFs, and audio files are stored as binary data. Binary files should be opened using binary modes such as "rb" or "wb".

binary_file.py
with open("photo.jpg", "rb") as file:
    data = file.read()

print(len(data))

Example Program

file_io.py
# Writing to a file
with open("test.txt", "w") as file:
    file.write("Hello, this is file I/O in Python.\n")
    file.write("Using context managers is recommended.")

# Reading from a file
with open("test.txt", "r") as file:
    content = file.read()
    print(content)

Common File Methods

  • read() – Reads the entire file.
  • readline() – Reads one line.
  • readlines() – Returns all lines as a list.
  • write() – Writes text to a file.
  • writelines() – Writes multiple lines.
  • close() – Closes the file (usually unnecessary when using with).

Common Mistakes

⚠️ Common Errors
  • Opening a file in "w" mode when you intended to append data.
  • Trying to read a file that does not exist.
  • Forgetting to use the with statement.
  • Using incorrect file paths.
  • Opening binary files in text mode.
  • Forgetting that read() returns a string.

Real-World Applications

File handling is used in almost every software application, including:

  • Saving game progress.
  • Creating log files.
  • Reading configuration settings.
  • Processing CSV and text files.
  • Generating reports.
  • Reading and writing documents.
  • Working with images and multimedia files.
  • Storing user preferences.

Summary

File handling allows Python programs to store and retrieve information from external files. In this lesson you learned how to open files, use different file modes, read and write text, append data, process files line by line, work with file paths, check for file existence, handle errors, and read binary files. These skills are essential for building practical applications that save and manage data outside the program.

🎯 Exercise 10

Write a program that creates a text file named notes.txt and writes 5 lines of diary notes into it. Then, reopen the file in read mode and print each line prefixed with its line number.

Bonus Challenges:

  1. Create a program that copies the contents of one file into another.
  2. Count the number of words, lines, and characters in a text file.
  3. Append today's date and time to a log file every time the program runs.
  4. Create a simple contact manager that stores names and phone numbers in a text file.
  5. Read a file containing student marks and calculate the average score.
Lecture 11 Β· Advanced Concepts

Exception Handling

Handling Errors Gracefully

Exceptions are errors detected during execution. If they are not handled, the program will terminate immediately. Python uses the try, except, else, and finally blocks to intercept and manage exceptions.

Exception Keywords

  • try: Contains the block of code that might raise an error.
  • except: Contains the code block that handles the specified exception.
  • else: Runs code that should execute only if no exceptions were raised.
  • finally: Executes cleanup code under all circumstances (with or without errors).
exceptions.py
try:
    num1 = int(input("Enter number: "))
    result = 100 / num1
except ZeroDivisionError:
    print("Error: You cannot divide by zero.")
except ValueError:
    print("Error: Invalid inputs. Please enter numbers.")
else:
    print(f"Result: {result}")
finally:
    print("Execution complete.")
🎯 Exercise 11

Write a function safe_divide(a, b) that returns a / b. Wrap the operation in a try-except block to handle division by zero errors, returning None if a division by zero occurs.

Lecture 12 Β· Advanced Concepts

OOP: Classes & Objects

Object-Oriented Programming (OOP)

Object-Oriented Programming is a paradigm that uses **Classes** (blueprints) and **Objects** (instances of classes) to organize code. Python is fully object-oriented, allowing custom classes to bundle data attributes and functions together.

Class Attributes and Constructors

The constructor method __init__ initializes an object's state when it is created. The self parameter represents the instance of the object being created, allowing access to its attributes and methods.

classes_objects.py
class Car:
    # Constructor
    def __init__(self, brand, year):
        self.brand = brand     # Instance attribute
        self.year = year       # Instance attribute
        self.speed = 0

    # Instance method
    def accelerate(self, amount):
        self.speed += amount
        print(f"The {self.brand} speed is now {self.speed} km/h.")

# Creating objects
my_car = Car("Toyota", 2022)
my_car.accelerate(50)  # Output: The Toyota speed is now 50 km/h.
🎯 Exercise 12

Create a class BankAccount with attributes owner and balance (starting at 0). Implement methods deposit(amount) and withdraw(amount). Withdrawals should verify sufficient funds before updating the balance.

Lecture 13 Β· Advanced Concepts

OOP: Inheritance & Polymorphism

Inheritance

Inheritance allows a new class (child/subclass) to inherit attributes and methods from an existing class (parent/superclass). This promotes code reuse and hierarchical class design. The super() function is used to call parent methods inside child classes.

Polymorphism

Polymorphism allows child classes to define unique behaviors for methods that share the same name as methods in parent classes (method overriding).

inheritance.py
class Animal:
    def __init__(self, name):
        self.name = name
    def make_sound(self):
        return "Generic Sound"

class Dog(Animal):
    # Method overriding (Polymorphism)
    def make_sound(self):
        return "Woof!"

class Cat(Animal):
    # Method overriding (Polymorphism)
    def make_sound(self):
        return "Meow!"

pets = [Dog("Buddy"), Cat("Luna")]
for pet in pets:
    print(f"{pet.name} says {pet.make_sound()}")
🎯 Exercise 13

Create a base class Shape with a method area() that returns 0. Define subclasses Rectangle (with width and height attributes) and Circle (with a radius attribute) that override the area() method to return their respective mathematical areas.

Lecture 14 Β· Advanced Concepts

Modules & Packages

Importing Standard Libraries

Python code is organized into modules (single .py files) and packages (folders of modules). You can use any external or built-in script by importing it via the import statement.

Popular Built-in Modules

  • math: Provides access to mathematical functions like sqrt(), sin(), and constants like pi.
  • random: Offers tools to generate random numbers and select random list elements.
  • datetime: Used for manipulating dates and times.
modules.py
import math
from random import randint, choice

# Use math
print(math.sqrt(16))  # 4.0

# Use random
num = randint(1, 100) # Random int between 1 and 100
colors = ["red", "green", "blue"]
chosen = choice(colors) # Select random element
Pip and Packages

Third-party libraries are hosted on PyPI (Python Package Index). You can install them via terminal command: pip install package_name (e.g., pip install requests).

🎯 Exercise 14

Write a script that uses the random module to generate a list of 6 random numbers between 1 and 49 (representing lottery numbers), sorts them in ascending order, and prints the result.

Lecture 15 Β· Advanced Concepts

Functional Programming

List Comprehensions

List comprehensions provide a concise way to create lists. They consist of brackets containing an expression followed by a for clause, then zero or more for or if clauses. They run faster and are cleaner than traditional loops.

Lambda Functions (Anonymous Functions)

A lambda function is a small anonymous function defined using the lambda keyword. It can take any number of arguments but can only have a single expression.

Map & Filter

  • map(func, iterable): Applies a function to all items in an input list.
  • filter(func, iterable): Filters list elements based on a function that returns a boolean.
functional.py
# List Comprehension
squares = [x**2 for x in range(1, 6)] # [1, 4, 9, 16, 25]

# Lambda function
double = lambda x: x * 2
print(double(5))  # 10

# Map & Filter
numbers = [1, 2, 3, 4, 5, 6]
evens = list(filter(lambda x: x % 2 == 0, numbers)) # [2, 4, 6]
doubled = list(map(lambda x: x * 2, numbers)) # [2, 4, 6, 8, 10, 12]
🎯 Exercise 15

Write a list comprehension that takes the list names = ["john", "sarah", "mary", "alex"] and returns a new list containing only names that start with "m", capitalized (e.g. ["Mary"]).

Lecture 16 Β· Advanced Concepts

Final Capstone Project

Project: Command-Line Contact Book

For your capstone project, you will build a command-line Contact Management application. This project consolidates everything you have learned: variables, conditionals, loops, functions, lists, dictionaries, files, exceptions, and OOP.

Project Requirements:

  1. Contact Class: Create a Contact class containing name, phone, and email attributes.
  2. ContactBook Class: Create a ContactBook class that manages a list of Contact objects.
  3. Persistent Storage: Load contacts from a text file on startup and save contacts back to the file upon exiting.
  4. User Menu: Provide a loop interface allowing users to:
    • View all contacts
    • Add a new contact
    • Search for a contact by name
    • Delete a contact
    • Save and Exit
  5. Exception Handling: Safely catch and handle potential errors (like inputting text when integers are expected, or opening a non-existent file).
project_stub.py
class Contact:
    def __init__(self, name, phone, email):
        self.name = name
        self.phone = phone
        self.email = email
    
    def __str__(self):
        return f"{self.name} | Phone: {self.phone} | Email: {self.email}"

class ContactBook:
    def __init__(self):
        self.contacts = []
    
    def add_contact(self, contact):
        self.contacts.append(contact)
        print("Contact added successfully.")

# Implement the rest of the ContactBook logic and main menu loop
🎯 Final Challenge

Write the complete script in a file named contacts.py. Run and test it by adding a few contacts, saving, exiting, and confirming the text file stores your entries correctly.