Classes & Object Oriented Programming Jump to this section

A class lets you create your own custom data type. Just like Python has built-in types like int, str, and list, you can create your own types, like Dog, BankAccount, or Person. A class bundles together related data (attributes) and actions (methods) into one neat package.


Creating a Class and An Instance Jump to this section

A class is defined using the class keyword, followed by the class name (usually starting with a capital letter).

class Dog:
    pass

my_dog = Dog()   # create an instance

A new object created from a class is called an instance. For example, my_dog = Dog() is an instance, and if another Dog was created (new_dog = Dog()), then there would be 2 instances of the Dog class.


The __init__ Method and self Jump to this section

Inside a class, you use the special __init__ method to set up each new object (it runs automatically when a new instance of the class is created).

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

    def bark(self):
        print(self.name + " says woof!")

fido = Dog("Fido", 3)  # inside Dog methods, self == fido
fido.bark()   # Fido says woof!

Inside a class, self refers to the current instance of the object. When we create my_dog = Dog("Fido", 3), Python creates the object and then calls Dog.__init__(my_dog, "Fido", 3). So, inside the method, self is my_dog. Writing self.name is saying “store name on this specific dog”. This allows each instance to have its own data.


Attributes and Methods Jump to this section

  • Attributes are variables attached to an instance (self.name).
  • Methods are functions that live inside a class. Their first parameter is always self, so they can access the object's data.

In this example:

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

    def bark(self):
        print(self.name + " says woof!")

name and age are attributes; bark() is a method.

You can access and change attributes directly:

print(fido.age)   # 3
fido.age = 4
print(fido.age)   # 4

Example: Simple Bank Account Jump to this section

class BankAccount:
    def __init__(self, owner, balance=0):   # creates an owner and a balance (balance has a default value of 0)
        self.owner = owner
        self.balance = balance

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

    def withdraw(self, amount):
        if amount <= self.balance:
            self.balance -= amount
            return True
        else:
            print(f"Withdrawal failed! You tried to take ${amount}, but only have ${self.balance}.")
            return False

my_account = BankAccount("John", 100)
my_account.deposit(50)
success = my_account.withdraw(30)
print(acct.balance, success)   # 120 True

Inheritance Jump to this section

Inheritance lets you create a new class (a "child" or "subclass") based on an existing class (a "parent" or "superclass"). The child class gets all the attributes and methods of the parent and can add its own or change existing ones.

# Parent Class (General)
class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        print("...")

# Child Class (Specific)
class Cat(Animal):
    # Cat automatically gets the __init__ method and 'name' attribute from Animal

    # We can override the parent's method with a more specific one
    def speak(self):
        print(self.name + " says meow")

    # We can also add NEW methods
    def purr(self):
        print(f"{self.name} purrs softly.")

# Another Child Class
class Dog(Animal):
    def speak(self):
        print(f"{self.name} says: Woof!")


whiskers = Cat("Whiskers")
fido = Dog("Fido")

whiskers.speak()  # Whiskers says: Meow!
whiskers.purr()   # Whiskers purrs softly.
fido.speak()      # Fido says: Woof!

Common Mistakes Jump to this section

  • Forgetting to include self as the first parameter on methods. def bark(): is wrong; use def bark(self):
  • Forgetting self when accessing attributes inside a method. print(name) is wrong; use print(self.name)

Challenge Jump to this section

Write a Person class that stores a name and an age. Add a method greet() that prints "Hello, my name is NAME". Create two people and call their greet() methods.

Hint

Create a class with __init__(self, name, age) and store self.name and self.age. Define greet(self) to print the message using self.name.


Show example solution
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def greet(self):
        print("Hello, my name is", self.name)

alice = Person("Alice", 30)
bob = Person("Bob", 25)
alice.greet()
bob.greet()

Key Takeaways Jump to this section

  • Use class to group related data and behavior.
  • __init__ sets up each instance and self is the instance inside methods.
  • Methods operate on self and can change instance attributes.
  • Inheritance lets a class reuse behavior from another class.
  • Keep class interfaces simple and avoid putting unrelated logic inside a class.