Lesson 18 of 25

Object-Oriented Programming: Classes & Objects

Defining Classes and Creating Objects

Object-Oriented Programming (OOP) is a programming paradigm that organizes code into classes and objects. A class is a blueprint that defines the attributes (data) and methods (functions) that objects of that type will have.

An object is an instance of a class. You can create multiple objects from the same class, each with its own attribute values. The __init__ method is a special constructor that runs when a new object is created.

Example
# Defining a class
class Dog:
    # Constructor — runs when creating a new Dog object
    def __init__(self, name, breed, age):
        self.name = name      # Instance attribute
        self.breed = breed
        self.age = age

    # Method
    def bark(self):
        return f"{self.name} says: Woof!"

    # Method with logic
    def human_years(self):
        return self.age * 7

    # String representation
    def __str__(self):
        return f"{self.name} ({self.breed}, {self.age} years)"

# Creating objects (instances)
dog1 = Dog("Buddy", "Golden Retriever", 3)
dog2 = Dog("Max", "German Shepherd", 5)

print(dog1.name)          # Buddy
print(dog1.bark())        # Buddy says: Woof!
print(dog1.human_years()) # 21
print(dog2)               # Max (German Shepherd, 5 years)
  • class ClassName: — defines a new class (use PascalCase for names)
  • __init__(self, ...) — constructor, called when creating an object
  • self — refers to the current instance (must be first parameter of every method)
  • self.attribute = value — create instance attributes inside __init__
  • __str__(self) — defines how the object is printed as a string
  • object = ClassName(args) — create a new instance
Try Creating a Class
JavaScript
class Dog:
    def __init__(self, name, breed, age):
        self.name = name
        self.breed = breed
        self.age = age

    def bark(self):
        return f"{self.name} says: Woof!"

    def __str__(self):
        return f"{self.name} ({self.breed}, age {self.age})"

dog = Dog("Buddy", "Golden Retriever", 3)
print(dog)
print(dog.bark())
print(f"{dog.name} in human years: {dog.age * 7}")
Notes
  • The 'self' parameter is how Python passes the object instance to its own methods. It's similar to 'this' in JavaScript or Java, but in Python you must explicitly include it.

Class Attributes vs Instance Attributes

Instance attributes are unique to each object (defined in __init__). Class attributes are shared by all instances of the class and are defined directly in the class body.

Understanding the difference is important — class attributes are useful for values that should be the same across all instances, like a species name or a counter.

Example
class Employee:
    # Class attribute — shared by all instances
    company = "TechCorp"
    employee_count = 0

    def __init__(self, name, role, salary):
        # Instance attributes — unique to each object
        self.name = name
        self.role = role
        self.salary = salary
        Employee.employee_count += 1  # Modify class attribute

    def display(self):
        print(f"{self.name} | {self.role} | ${self.salary:,} | {self.company}")

# Create employees
emp1 = Employee("Alice", "Developer", 95000)
emp2 = Employee("Bob", "Designer", 85000)
emp3 = Employee("Charlie", "Manager", 105000)

emp1.display()  # Alice | Developer | $95,000 | TechCorp
emp2.display()  # Bob | Designer | $85,000 | TechCorp

# Access class attribute
print(f"Total employees: {Employee.employee_count}")  # 3
Try Class vs Instance Attributes
JavaScript
class Employee:
    company = "TechCorp"
    count = 0

    def __init__(self, name, role):
        self.name = name
        self.role = role
        Employee.count += 1

emp1 = Employee("Alice", "Developer")
emp2 = Employee("Bob", "Designer")

print(f"{emp1.name}: {emp1.role} at {emp1.company}")
print(f"{emp2.name}: {emp2.role} at {emp2.company}")
print(f"Total employees: {Employee.count}")
Notes
  • Be careful modifying class attributes through an instance (e.g., emp1.company = 'NewCorp'). This creates a new instance attribute that shadows the class attribute rather than changing it for all instances.