Lesson 2 · Python for Data Analysts
Python Zero to Hero: The Complete Beginner-to-Advanced Course
One notebook, start to finish: from your very first print() to decorators, generators, and object-oriented programming. No prior experience needed. Let's…
- CoursePython for Data Analysts
- Lesson2 of 12
- Video1 h 3 min
- FormatJupyter notebook · 46 code cells
What you'll learn
Data
No separate download needed — the notebook creates or downloads everything it uses.
📓 Full notebook
Download .ipynbPython Zero to Hero: The Complete Beginner-to-Advanced Course#
- One notebook, start to finish: from your very first print() to decorators, generators, and object-oriented programming.
- No prior experience needed. Let's get straight into it.
Before You Start#
- Install Python 3 from python.org (on Windows, check 'Add python.exe to PATH'), then install VS Code from code.visualstudio.com with its Python and Jupyter extensions.
- Open the Command Palette (Control/Command plus Shift plus P), run 'Create: New Jupyter Notebook', and select your Python interpreter as the kernel.
Part 1: Fundamentals#
Your First Cell: print()#
print('Hello, world!')
print(42)
Data Types: Strings, Integers, Floats, Booleans#
- Text values are strings, written with single or double quotes.
- Whole numbers are integers; numbers with a decimal point are floats.
- True/False values are booleans, always capitalized in Python.
a_string = 'Python is fun'
an_integer = 25
a_float = 3.14
a_boolean = True
print(type(a_string), type(an_integer), type(a_float), type(a_boolean))
Variables and Naming#
student_name = 'Jordan'
student_age = 19
print(student_name, student_age)
student_age = 20
print(student_name, student_age)
f-Strings: Combining Text and Values#
price = 19.99
quantity = 3
total = price * quantity
print(f'{quantity} items at ${price} each comes to ${total:.2f}')
Arithmetic and Operators#
print(7 + 3)
print(7 - 3)
print(7 * 3)
print(7 / 3)
print(7 // 3)
print(7 % 3)
print(7 ** 2)
Type Conversion (Casting)#
age_text = '25'
age_number = int(age_text)
print(age_number + 1)
print(str(age_number) + ' years old')
Getting Input From the User#
name = input('What is your name? ')
print(f'Nice to meet you, {name}!')
Conditionals: if, elif, else#
- if, elif, and else let a program branch: run one block of code when a condition is true, and a different block otherwise.
score = 82
if score >= 90:
grade = 'A'
elif score >= 80:
grade = 'B'
elif score >= 70:
grade = 'C'
else:
grade = 'F'
print(f'Score {score} is a grade {grade}')
Comparison and Logical Operators#
age = 25
has_ticket = True
print(age >= 18 and has_ticket)
print(age < 18 or not has_ticket)
print(age == 25)
print(age != 30)
Part 2: Data Structures#
Lists: Ordered, Changeable Collections#
fruits = ['apple', 'banana', 'cherry']
print(fruits[0])
print(fruits[-1])
fruits.append('date')
fruits.remove('banana')
print(fruits)
print(len(fruits))
numbers = [5, 2, 9, 1, 7]
print(numbers[1:4])
numbers.sort()
print(numbers)
numbers.sort(reverse=True)
print(numbers)
Tuples: Ordered, Unchangeable Collections#
point = (3, 7)
print(point[0], point[1])
x, y = point
print(f'x is {x}, y is {y}')
Sets: Unique, Unordered Values#
tags = {'python', 'coding', 'python', 'tutorial'}
print(tags)
tags.add('beginner')
print('python' in tags)
Dictionaries: Key-Value Pairs#
person = {'name': 'Alex', 'age': 30, 'city': 'Austin'}
print(person['name'])
person['age'] = 31
person['job'] = 'Engineer'
print(person)
for key, value in person.items():
print(f'{key}: {value}')
Comprehensions: Building Collections in One Line#
squares = [n ** 2 for n in range(1, 6)]
print(squares)
evens = [n for n in range(1, 11) if n % 2 == 0]
print(evens)
words = ['python', 'is', 'fun']
word_lengths = {word: len(word) for word in words}
print(word_lengths)
Part 3: Loops#
for Loops and range()#
for number in range(5):
print(number)
for fruit in ['apple', 'banana', 'cherry']:
print(fruit.upper())
while Loops, break, and continue#
count = 0
while count < 10:
count += 1
if count == 3:
continue
if count == 7:
break
print(count)
Part 4: Functions#
Defining and Calling Functions#
def greet(name):
"""Return a friendly greeting for the given name."""
return f'Hello, {name}!'
print(greet('Sam'))
Default Parameters and Keyword Arguments#
def make_coffee(size='medium', extra_shot=False):
shot_text = ' with an extra shot' if extra_shot else ''
return f'One {size} coffee{shot_text}, coming up!'
print(make_coffee())
print(make_coffee('large'))
print(make_coffee(extra_shot=True, size='small'))
*args and **kwargs: Flexible Argument Counts#
def total_cost(*prices, **fees):
subtotal = sum(prices)
extra = sum(fees.values())
return subtotal + extra
print(total_cost(10, 20, 30))
print(total_cost(10, 20, tax=5, shipping=8))
Lambda Functions#
square = lambda n: n ** 2
print(square(6))
people = [('Sam', 34), ('Ana', 22), ('Kai', 45)]
people.sort(key=lambda person: person[1])
print(people)
Variable Scope#
counter = 0
def increment():
global counter
counter += 1
increment()
increment()
print(counter)
Part 5: Error Handling#
try, except, else, finally#
def safe_divide(a, b):
try:
result = a / b
except ZeroDivisionError:
print('Cannot divide by zero.')
return None
else:
print('Division succeeded.')
return result
finally:
print('Division attempt finished.')
print(safe_divide(10, 2))
print(safe_divide(10, 0))
Catching Multiple Exception Types#
def get_item(items, index):
try:
return items[index]
except IndexError:
return 'That index does not exist.'
except TypeError:
return 'The index must be a whole number.'
fruits = ['apple', 'banana']
print(get_item(fruits, 5))
print(get_item(fruits, 'first'))
Custom Exceptions#
class InsufficientFundsError(Exception):
"""Raised when a withdrawal exceeds the available balance."""
pass
def withdraw(balance, amount):
if amount > balance:
raise InsufficientFundsError(f'Cannot withdraw {amount}, balance is only {balance}')
return balance - amount
try:
withdraw(100, 250)
except InsufficientFundsError as e:
print(f'Transaction failed: {e}')
Part 6: Working With Files#
Reading and Writing Text Files#
with open('notes.txt', 'w') as f:
f.write('Line one\n')
f.write('Line two\n')
print('File written.')
with open('notes.txt', 'r') as f:
contents = f.read()
print(contents)
with open('notes.txt', 'r') as f:
for line in f:
print('Line:', line.strip())
Writing Your Own Context Manager#
class Timer:
def __enter__(self):
import time
self.start = time.time()
return self
def __exit__(self, exc_type, exc_value, traceback):
import time
elapsed = time.time() - self.start
print(f'Elapsed: {elapsed:.4f} seconds')
with Timer():
total = sum(n * n for n in range(1_000_000))
print(total)
Part 7: Modules, Packages, and Environments#
Modules and the Standard Library#
- Every Python file is a module. import brings functions, variables, and classes from one module into another.
- Python's standard library ships dozens of built-in modules for common tasks, with nothing extra to install.
import math
import random
import datetime
print(math.sqrt(81))
print(random.choice(['heads', 'tails']))
print(datetime.date.today())
Packages, pip, and Virtual Environments#
- External packages live on PyPI and install with pip: 'pip install package_name'.
- A virtual environment is an isolated set of installed packages for one project, so different projects can use different, even conflicting, package versions without interfering with each other.
- Create one with 'python -m venv venv', then activate it before installing anything: 'venv\Scripts\activate' on Windows, or 'source venv/bin/activate' on macOS/Linux.
Part 8: Regular Expressions#
Pattern Matching With re#
import re
text = 'Contact us at support@example.com or sales@example.com'
emails = re.findall(r'[\w.]+@[\w.]+', text)
print(emails)
sentence = 'There are 12 apples and 5 oranges'
numbers = re.findall(r'\d+', sentence)
print(numbers)
cleaned = re.sub(r'\d+', '#', sentence)
print(cleaned)
Part 9: Iterators and Generators#
Generator Functions With yield#
def countdown(start):
while start > 0:
yield start
start -= 1
yield 'Liftoff!'
for value in countdown(3):
print(value)
squares_gen = (n ** 2 for n in range(1_000_000))
print(type(squares_gen))
print(next(squares_gen))
print(next(squares_gen))
Part 10: Decorators#
Functions as First-Class Objects#
def shout(text):
return text.upper() + '!'
def apply_twice(func, value):
return func(func(value))
print(apply_twice(shout, 'hello'))
Writing a Decorator#
def log_calls(func):
def wrapper(*args, **kwargs):
print(f'Calling {func.__name__} with {args}')
result = func(*args, **kwargs)
print(f'{func.__name__} returned {result}')
return result
return wrapper
@log_calls
def add(a, b):
return a + b
add(3, 4)
Part 11: Object-Oriented Programming#
Classes and Objects#
class Animal:
def __init__(self, name, sound):
self.name = name
self.sound = sound
def make_sound(self):
return f'{self.name} says {self.sound}'
generic_animal = Animal('Creature', '...')
print(generic_animal.make_sound())
Inheritance and Polymorphism#
class Dog(Animal):
def __init__(self, name):
super().__init__(name, 'Woof')
def fetch(self):
return f'{self.name} fetches the ball!'
class Cat(Animal):
def __init__(self, name):
super().__init__(name, 'Meow')
dog = Dog('Rex')
cat = Cat('Whiskers')
for animal in [dog, cat]:
print(animal.make_sound())
The str Method#
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f'Point({self.x}, {self.y})'
p = Point(3, 4)
print(p)
Part 12: Basic Unit Testing#
Writing Tests With unittest#
- A unit test checks that one small piece of code behaves the way you expect, automatically, so you find out immediately if a change breaks something.
- Python's built-in unittest module provides a standard structure for writing and running tests.
import unittest
def add(a, b):
return a + b
class TestAdd(unittest.TestCase):
def test_positive_numbers(self):
self.assertEqual(add(2, 3), 5)
def test_negative_numbers(self):
self.assertEqual(add(-1, -1), -2)
runner = unittest.TextTestRunner(verbosity=0)
runner.run(unittest.TestLoader().loadTestsFromTestCase(TestAdd))
Capstone Project: Word Frequency Analyzer#
- Let's build one real program that pulls together nearly everything from this lesson: file I/O, regex, comprehensions, a custom exception, a decorator, and a class.
- It reads a text file and reports its most frequently used words.
sample_text = (
'Python is fun. Python is powerful. '
'Learning Python takes practice, but Python rewards practice.'
)
with open('sample.txt', 'w') as f:
f.write(sample_text)
print('sample.txt created.')
class EmptyFileError(Exception):
"""Raised when a file has no readable words in it."""
pass
def timed(func):
def wrapper(*args, **kwargs):
import time
start = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - start
print(f'{func.__name__} took {elapsed:.5f} seconds')
return result
return wrapper
class WordFrequencyAnalyzer:
def __init__(self, filepath):
self.filepath = filepath
def load_words(self):
with open(self.filepath, 'r') as f:
text = f.read()
words = re.findall(r"[a-z']+", text.lower())
if not words:
raise EmptyFileError(f'{self.filepath} has no readable words.')
return words
@timed
def top_words(self, n=3):
words = self.load_words()
counts = {word: words.count(word) for word in set(words)}
ranked = sorted(counts.items(), key=lambda pair: pair[1], reverse=True)
return ranked[:n]
analyzer = WordFrequencyAnalyzer('sample.txt')
print(analyzer.top_words(3))
with open('empty.txt', 'w') as f:
pass
empty_analyzer = WordFrequencyAnalyzer('empty.txt')
try:
empty_analyzer.top_words()
except EmptyFileError as e:
print(f'Analysis failed: {e}')
Wrap-Up: What You Learned#
- Fundamentals: variables, data types, f-strings, operators, casting, user input, conditionals, and boolean logic.
- Data structures: lists, tuples, sets, dictionaries, and comprehensions.
- Loops: for, while, range, break, and continue.
- Functions: parameters, defaults, keyword arguments, *args/**kwargs, lambdas, and scope.
- Error handling: try/except/else/finally and custom exceptions.
- Files and context managers, including writing your own with enter and exit.
- Modules, packages, pip, and virtual environments.
- Regular expressions with the re module.
- Iterators and generators with yield.
- Decorators, and functions as first-class objects.
- Object-oriented programming: classes, inheritance, polymorphism, and dunder methods.
- Basic unit testing with unittest.
- A capstone project combining nearly all of it into one working program.
- You just went from print('Hello, world!') to writing decorators, generators, and tested, exception-safe classes, in one sitting. That's genuinely rare. If you want the next build to land in your feed automatically, subscribing is the move see you in the next one.
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



