Weekly Learning Theme: Functions and Classes in Python

This week was a major milestone in my Python journey: I finally wrapped my head around functions and classes! At first, I thought they were just fancier blocks of code, but after practicing, I realized they are the foundation of clean, powerful programs.

Here’s what I learned, with real examples to make it stick.

Functions: The First Big Step

Functions are like small machines inside your program. You give them input (if needed), they do a job, and optionally give back a result.

Example: A simple greeting function.

def greet_user(name):
    """Say hello to the user."""
    print(f"Hello, {name.title()}!")

# Calling the function
greet_user('alice')

Why Functions Matter

  • Avoid repetition: Write once, call many times.
  • Easier debugging: If something breaks, you know exactly where to look.
  • Cleaner programs: Main code becomes just a series of meaningful steps.

Types of Function Arguments

  • Positional: Order matters
  • Keyword: Specify by name
  • Default: Pre-set values
  • Arbitrary: Catch-all with *args or **kwargs

Example using default values:

def describe_pet(pet_name, animal_type='dog'):
    print(f"I have a {animal_type} named {pet_name.title()}.")

describe_pet('willie')

Without functions, my programs felt like messy kitchens. Functions gave them organization, like labeled drawers and shelves.

Return Values: Functions That Talk Back

Functions can also return information instead of just printing it.

def get_formatted_name(first, last, middle=''):
    if middle:
        full_name = f"{first} {middle} {last}"
    else:
        full_name = f"{first} {last}"
    return full_name.title()

musician = get_formatted_name('john', 'hooker', 'lee')
print(musician)

Now the function is smarter and reusable for both two-part and three-part names!

Organizing Functions into Modules

As programs grew, I learned to put functions in separate .py files called modules.

# pizza.py

def make_pizza(size, *toppings):
    print(f"Making a {size}-inch pizza with:")
    for topping in toppings:
        print(f"- {topping}")

Then I imported them neatly:

# making_pizzas.py
import pizza

pizza.make_pizza(12, 'mushrooms', 'green peppers')

Modules = organized toolbox. Game-changer!

But… Functions Have Limits

While functions made code manageable, I ran into a new problem: what if my program needed to keep track of both data and behavior for complex things, like a car’s make, model, and mileage?

That’s where classes come in.

Classes: The Next Big Leap

Classes combine data and functions into one structure. They let you create objects with both attributes (info) and methods (actions).

Here’s a real example:

class Dog:
    """A simple attempt to model a dog."""

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def sit(self):
        print(f"{self.name.title()} is now sitting.")

    def roll_over(self):
        print(f"{self.name.title()} rolled over!")

# Create an instance
my_dog = Dog('willie', 6)

# Access attributes and call methods
print(f"My dog's name is {my_dog.name.title()}.")
my_dog.sit()

Breaking It Down

  • Class: Template for something (like Dog)
  • Instance: Actual object you create (like my_dog)
  • Attributes: Variables tied to the object (name, age)
  • Methods: Functions tied to the object (sit, roll_over)

Difference vs Functions:

FunctionsClasses
Perform a taskRepresent things with data + behaviors
StandaloneCreate reusable templates (objects)
Great for simple actionsEssential for complex programs

Real Example: Why Use a Class?

Imagine a game where players have cars. A function alone could maybe print the car’s model. But with a class, each player’s car can store its make, model, year, mileage, and act differently (drive, refuel, etc).

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0

    def get_descriptive_name(self):
        return f"{self.year} {self.make} {self.model}"

    def read_odometer(self):
        print(f"This car has {self.odometer_reading} miles on it.")

Now you have mini-programs (objects) inside your bigger program. It’s like magic!

Reflection: Functions vs Classes

When I started Python, I was overwhelmed by the idea of “object-oriented programming” (OOP). But now I see:

  • Use functions to do things.
  • Use classes to model real-world things and attach behaviors to them.

Functions keep code clean. Classes create powerful models that can “live” and “behave” inside your programs.

Next up, I’ll dive into inheritance — where new classes can reuse and extend old ones. Can’t wait!

If you’re just starting out, take it step by step. Master functions first. Then you’ll be ready for classes. They’re not two different worlds — they build on each other.


Thanks for reading, and let’s see what the tide brings tomorrow!


Join Me on My Journey

If you’d like to follow along, I’ll be sharing more about my learning process, projects, and insights here and on my GitHub repository. Feel free to connect — I’d love to hear about your coding journey too!