Skip to Content
Course content

115: Classes and Objects: The Basics

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've seen this exact snippet of code dozens of times when mentoring junior devs. It looks perfectly logical at first glance, but the moment you run it, Python throws an error that seems to make no sense.

class User:
    def __init__(self, username, email):
        self.username = username
        self.email = email

    def welcome_message():
        print(f"Welcome back, {self.username}!")

user1 = User("dev_dan", "dan@example.com")
user1.welcome_message()

If you run this, you'll get a TypeError: welcome_message() takes 0 positional arguments but 1 was given. You're probably looking at the call user1.welcome_message() and thinking, "I didn't give it any arguments! The parentheses are empty!"

The Hidden Argument Problem

Here is what's happening behind the scenes: in Python, when you call a method on an object, Python automatically passes the object itself as the first argument. So, user1.welcome_message() is actually executed as User.welcome_message(user1).

Because our definition of welcome_message() doesn't accept any arguments, Python complains that it received one (the user1 object) when it expected zero. This is why you see self everywhere in Python classes. It isn't a keyword, but it is a very strong convention. It's our way of saying, "This method needs to know which specific object it's working with."

Fixing the Method Signature

To fix this, we just need to tell the method to expect that object. We do this by adding self as the first parameter.

class User:
    def __init__(self, username, email):
        self.username = username
        self.email = email

    # Added 'self' here
    def welcome_message(self):
        print(f"Welcome back, {self.username}!")

user1 = User("dev_dan", "dan@example.com")
user1.welcome_message() # Now this works!

Blueprints versus Actual Houses

To wrap your head around classes and objects, I find it easiest to think of a Class as a blueprint. If you have a blueprint for a house, you can't live in the blueprint. It's just a piece of paper that describes where the walls go and where the plumbing is. It defines the structure.

An Object (or an Instance) is the actual house built from that blueprint. You can build ten different houses from one blueprint. They all have the same structure, but one might be painted blue, one might be red, and one might have a different family living inside. In Python terms, the "paint color" is what we call an instance variable.

The Role of __init__

You'll notice the __init__ method in the examples above. I call this the "setup" method. It's a special method that Python runs automatically the moment you create a new object. Its primary job is to assign the initial state to the object.

When we write self.username = username, we are taking the value passed in during creation and "sticking" it to the object. Without that self. prefix, the variable would just be a local variable inside the function and would disappear as soon as __init__ finished running.

Grouping Data and Behavior

The real power of this approach is that we stop having disconnected pieces of data. Instead of having a list of usernames and a separate list of emails, we have a User object that carries its own data and its own functions (methods) to manipulate that data.

  • Class: The blueprint (e.g., User).
  • Object: The instance (e.g., user1).
  • Attribute: A variable tied to the object (e.g., self.email).
  • Method: A function tied to the object (e.g., welcome_message()).



📋 Practical Task

Building a Digital Library Catalog

You need to create a system to track books in a library. Your task is to build a Book class that manages the status of a book.

Requirements:

  • Create a class named Book.
  • The __init__ method should take three parameters: title, author, and isbn.
  • The __init__ method should also create an attribute called is_checked_out and set it to False by default.
  • Add a method called borrow_book(). If the book is not checked out, it should set is_checked_out to True and print "You have borrowed [title]". If it is already checked out, it should print "Sorry, [title] is already taken".
  • Add a method called return_book(). It should set is_checked_out to False and print "You have returned [title]".

Test your code by:

  1. Creating an instance of a book (e.g., "The Hobbit" by J.R.R. Tolkien).
  2. Calling borrow_book() once to check it out.
  3. Calling borrow_book() a second time to ensure it tells you the book is already taken.
  4. Calling return_book() and then borrowing it successfully again.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.