- Class definition syntax — how to define a class
- The __init__ method — the constructor that initializes objects
- Creating attributes — what data objects will hold
- Creating methods — what behaviors objects will have
- Instantiation — creating objects from classes
- Working with objects — accessing and modifying objects
Creating Classes and Objects
Creating classes and objects is the foundation of Object-Oriented Programming in Python. It's like learning how to build with LEGO — once you know how to create your own pieces, you can build anything. In this tutorial, we'll walk through the entire process step by step.
What we'll cover: We'll start with the basic syntax of a class definition, then add attributes and methods, and finally create objects from our class. By the end, you'll be able to create your own classes and objects with confidence.
💡 Key concept: Creating a class is about defining a new type of object. Creating an object is about making a specific instance of that type. The class defines the structure; the object is the actual thing that exists in memory.
Class Definition Syntax
Writing Your First Class
The syntax for defining a class in Python is straightforward. You use the class keyword, followed by the class name, and then a colon. The body of the class is indented, just like a function or loop.
Definition: A class is defined using the class keyword. The class name should use CapitalizedWords convention (also called PascalCase), where each word starts with a capital letter.
# Basic class definition syntax
# 1. The simplest class (empty class)
class EmptyClass:
"""This is an empty class"""
pass
# 2. A class with a docstring
class Person:
"""A class representing a person"""
pass
# 3. A class with attributes and methods
class Dog:
"""A class representing a dog"""
# Class attribute (shared by all dogs)
species = "Canis familiaris"
# __init__ method (constructor)
def __init__(self, name, age):
# Instance attributes (unique to each dog)
self.name = name
self.age = age
# Method (behavior)
def bark(self):
return f"{self.name} says Woof!"
# Let's examine the parts:
# 1. 'class' - the keyword to define a class
# 2. 'Dog' - the class name (PascalCase)
# 3. '"""..."""' - the docstring (documentation)
# 4. 'species' - a class attribute (shared)
# 5. '__init__' - the constructor method
# 6. 'self.name' - an instance attribute
# 7. 'bark' - a method (behavior)
Key points about class syntax:
- class keyword — starts the class definition
- Class name — use PascalCase (e.g., MyClass, Person, BankAccount)
- Docstring — optional but recommended documentation
- Indentation — all class members must be indented
- pass — can be used for an empty class
Class naming conventions:
- PascalCase — each word starts with a capital letter
- Singular nouns — use "Dog" not "Dogs"
- Descriptive names — make it clear what the class represents
- Avoid abbreviations — use "Customer" not "Cust"
Quick Check: What keyword is used to define a class? (Answer: class)
The __init__ Method
The Constructor — Setting Up New Objects
The __init__ method is a special method in Python classes. It's called automatically when you create a new object. Its purpose is to initialize the object's attributes — to set up the initial state of the object.
Definition: The __init__ method is the constructor of a class. It's called when an object is instantiated and is used to initialize the object's attributes. The first parameter is always self, which refers to the object being created.
# Understanding the __init__ method
class Book:
"""A class representing a book"""
def __init__(self, title, author, pages):
"""
Initialize a new Book object.
Args:
title (str): The title of the book
author (str): The author of the book
pages (int): The number of pages
"""
print(f"Creating a new book: {title}")
self.title = title
self.author = author
self.pages = pages
self.is_open = False # Default value
def open(self):
self.is_open = True
return f"Opening '{self.title}'"
def close(self):
self.is_open = False
return f"Closing '{self.title}'"
# When we create an object, __init__ is called automatically
book1 = Book("Python Guide", "John Smith", 350)
# Output: Creating a new book: Python Guide
book2 = Book("Data Science", "Jane Doe", 420)
# Output: Creating a new book: Data Science
# Each object has its own attributes
print(book1.title) # Python Guide
print(book2.title) # Data Science
# The __init__ method set up each object correctly
print(book1.open()) # Opening 'Python Guide'
print(book2.open()) # Opening 'Data Science'
# What happens in __init__:
# 1. self = the new object being created
# 2. self.title = title (assigns the title to the object)
# 3. The object is returned automatically
Key points about __init__:
- Called automatically — runs when an object is created
- self parameter — always the first parameter, refers to the new object
- Initializes attributes — sets up the object's initial state
- Default values — can assign default values to attributes
- No return needed — the object is returned automatically
- Optional — you can have a class without __init__
Common __init__ patterns:
- Required parameters — must be provided when creating an object
- Default values — optional parameters with defaults
- Validation — can check or validate parameter values
- Calculated attributes — can set attributes based on parameters
Quick Check: What is the purpose of the __init__ method? (Answer: To initialize the object's attributes when it's created)
Creating Attributes
What Data Objects Will Hold
Attributes are the data that belongs to an object. They represent the state or characteristics of the object. In Python, attributes are created by assigning values to self (inside the class) or directly to the object (outside the class).
Definition: Attributes are variables that belong to an object. They store the object's data. Attributes can be set when the object is created (in __init__) or added later.
# Creating attributes in a class
class Product:
"""A class representing a product"""
# Class attribute (shared by all instances)
category = "Electronics"
def __init__(self, name, price):
# Instance attributes (unique to each instance)
self.name = name
self.price = price
self.in_stock = True # Default value
self.rating = 0 # Default value
def __str__(self):
return f"{self.name} (${self.price})"
# 1. Creating objects sets up their attributes
laptop = Product("Laptop", 999.99)
phone = Product("Phone", 599.99)
# Each object has its own attributes
print(laptop.name) # Laptop
print(phone.name) # Phone
print(laptop.price) # 999.99
print(phone.price) # 599.99
# 2. Class attributes are shared
print(Product.category) # Electronics
print(laptop.category) # Electronics
print(phone.category) # Electronics
# 3. Adding new attributes to an object (only that object)
laptop.brand = "Apple"
print(laptop.brand) # Apple
# print(phone.brand) # AttributeError
# 4. Modifying attributes
laptop.price = 899.99
print(laptop.price) # 899.99
# 5. Attributes can be any data type
class Person:
def __init__(self, name, age, hobbies, is_student):
self.name = name # String
self.age = age # Integer
self.hobbies = hobbies # List
self.is_student = is_student # Boolean
person = Person("Alice", 25, ["reading", "coding"], True)
print(person.hobbies) # ['reading', 'coding']
print(person.is_student) # True
Types of attributes:
- Instance attributes — belong to each object individually, defined with
self - Class attributes — belong to the class itself, shared by all objects
- Dynamic attributes — can be added to objects after creation
- Private attributes — with a leading underscore _ to indicate they should not be accessed directly
Attribute naming conventions:
- Snake_case — use lowercase with underscores: first_name, customer_id
- Descriptive names — make it clear what the attribute represents
- Avoid abbreviations — use "customer_name" not "c_n"
- Class attributes — often uppercase: MAX_SIZE, DEFAULT_TIMEOUT
Quick Check: What is the difference between instance and class attributes? (Answer: Instance attributes belong to each object; class attributes are shared by all objects)
Creating Methods
What Behaviors Objects Will Have
Methods are functions that belong to an object. They define the behavior of the object — what it can do. Methods can access and modify the object's attributes, and they can accept parameters like regular functions.
Definition: Methods are functions defined inside a class. They describe the behaviors of objects. The first parameter of a method is always self, which refers to the object calling the method.
# Creating methods in a class
class BankAccount:
"""A class representing a bank account"""
def __init__(self, account_number, balance=0):
self.account_number = account_number
self.balance = balance
self.transactions = []
# 1. Basic method
def get_balance(self):
"""Return the current balance"""
return self.balance
# 2. Method with parameters
def deposit(self, amount):
"""Deposit money into the account"""
if amount > 0:
self.balance += amount
self.transactions.append(f"Deposited: +${amount}")
return f"Deposited ${amount}. New balance: ${self.balance}"
else:
return "Invalid deposit amount"
# 3. Method with multiple parameters
def withdraw(self, amount, fee=0):
"""Withdraw money from the account with optional fee"""
total_withdraw = amount + fee
if total_withdraw <= self.balance and amount > 0:
self.balance -= total_withdraw
self.transactions.append(f"Withdrew: -${amount} (fee: ${fee})")
return f"Withdrew ${amount}. New balance: ${self.balance}"
else:
return f"Insufficient funds. Balance: ${self.balance}"
# 4. Method that returns a value
def get_transaction_history(self):
"""Return the transaction history"""
return self.transactions
# 5. Method that modifies the object's state
def transfer(self, target_account, amount):
"""Transfer money to another account"""
if amount <= self.balance:
self.withdraw(amount)
target_account.deposit(amount)
return f"Transferred ${amount} to account {target_account.account_number}"
else:
return "Insufficient funds for transfer"
# Creating and using the class
account1 = BankAccount("A001", 1000)
account2 = BankAccount("A002", 500)
print(account1.deposit(200)) # Deposited $200. New balance: $1200
print(account1.withdraw(150)) # Withdrew $150. New balance: $1050
print(account1.transfer(account2, 300)) # Transferred $300 to account A002
print(f"Account 1 balance: ${account1.get_balance()}") # $750
print(f"Account 2 balance: ${account2.get_balance()}") # $800
print(account1.get_transaction_history())
# ['Deposited: +$200', 'Withdrew: -$150 (fee: $0)', 'Withdrew: -$300 (fee: $0)']
Types of methods:
- Instance methods — the most common type, can access and modify attributes
- Class methods — methods that operate on the class itself (using @classmethod)
- Static methods — methods that don't depend on the class or instance (using @staticmethod)
- Special methods — like __init__, __str__, __len__, etc.
Method naming conventions:
- Snake_case — use lowercase with underscores: get_balance, deposit_money
- Verbs — method names should start with verbs (get, set, calculate, process)
- Descriptive — make it clear what the method does
- Avoid abbreviations — use "calculate_total" not "calc_tot"
Quick Check: What is the first parameter of an instance method? (Answer: self)
Instantiating Objects
Creating Objects from Classes
Instantiation is the process of creating an object from a class. It's like using a blueprint to build a house. You call the class name like a function, passing any required arguments. The result is a new object that follows the blueprint defined by the class.
Definition: Instantiation is the creation of an object from a class. The class is called like a function, which creates a new object, calls the __init__ method, and returns the new object.
# Creating objects (instantiation) from classes
class Student:
"""A class representing a student"""
school = "Python Academy"
def __init__(self, name, student_id, grade=9):
self.name = name
self.student_id = student_id
self.grade = grade
self.courses = []
def enroll(self, course):
self.courses.append(course)
return f"{self.name} enrolled in {course}"
def get_info(self):
return f"{self.name} (ID: {self.student_id}) - Grade {self.grade}"
# 1. Basic instantiation
alice = Student("Alice", "S001")
print(alice.get_info()) # Alice (ID: S001) - Grade 9
# 2. Instantiation with custom values
bob = Student("Bob", "S002", 10)
print(bob.get_info()) # Bob (ID: S002) - Grade 10
# 3. Multiple objects from the same class
students = [
Student("Charlie", "S003", 11),
Student("Diana", "S004", 10),
Student("Eve", "S005", 9)
]
# 4. Storing objects in a list
for student in students:
print(student.get_info())
student.enroll("Math")
student.enroll("Science")
# 5. Using objects in a dictionary
classroom = {
"teacher": "Mr. Smith",
"students": students,
"room_number": "A101"
}
# 6. Creating objects with default values
class Car:
def __init__(self, make="Toyota", model="Camry", year=2020):
self.make = make
self.model = model
self.year = year
def get_info(self):
return f"{self.year} {self.make} {self.model}"
default_car = Car() # Uses all defaults
custom_car = Car("Honda", "Civic", 2023)
print(default_car.get_info()) # 2020 Toyota Camry
print(custom_car.get_info()) # 2023 Honda Civic
What happens during instantiation:
- Memory allocation — memory is reserved for the new object
- __init__ called — the constructor initializes the object
- self is set — self refers to the new object
- Attributes set — attributes are assigned
- Object returned — the new object is returned to the caller
Ways to instantiate:
- Simple — ClassName() with no arguments
- With arguments — ClassName(arg1, arg2) for required attributes
- With keyword arguments — ClassName(name="Alice", age=25)
- From a list — use * to unpack: ClassName(*list_data)
- From a dictionary — use ** to unpack: ClassName(**dict_data)
Quick Check: What is the process of creating an object called? (Answer: Instantiation)
Working with Objects
Using Objects in Your Programs
Once you've created objects, you need to work with them. This involves accessing their attributes, calling their methods, and managing collections of objects. Understanding how to work with objects is essential for effective OOP.
# Working with objects after creation
class Book:
"""A class representing a book"""
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
self.is_borrowed = False
def borrow(self):
if not self.is_borrowed:
self.is_borrowed = True
return f"{self.title} has been borrowed"
else:
return f"{self.title} is already borrowed"
def return_book(self):
if self.is_borrowed:
self.is_borrowed = False
return f"{self.title} has been returned"
else:
return f"{self.title} was not borrowed"
def get_status(self):
status = "Borrowed" if self.is_borrowed else "Available"
return f"{self.title} by {self.author} - {status}"
# 1. Creating objects
book1 = Book("Python Guide", "John Smith", 350)
book2 = Book("Data Science", "Jane Doe", 420)
book3 = Book("Web Development", "Bob Johnson", 280)
# 2. Accessing attributes
print(book1.title) # Python Guide
print(book1.author) # John Smith
print(book1.pages) # 350
# 3. Calling methods
print(book1.borrow()) # Python Guide has been borrowed
print(book1.get_status()) # Python Guide by John Smith - Borrowed
# 4. Modifying attributes
book1.pages = 360
print(f"Updated pages: {book1.pages}") # 360
# 5. Working with collections of objects
books = [book1, book2, book3]
# 6. Filtering objects
available_books = [book for book in books if not book.is_borrowed]
print("Available books:", [b.title for b in available_books])
# 7. Performing operations on objects
for book in books:
print(book.get_status())
# 8. Creating functions that work with objects
def display_books(book_list):
"""Display information about books"""
print("Library Catalog:")
for book in book_list:
print(f" {book.get_status()}")
display_books(books)
Common object operations:
- Access attributes — object.attribute_name
- Call methods — object.method_name(arguments)
- Modify attributes — object.attribute_name = new_value
- Store in collections — lists, dictionaries, sets of objects
- Filter objects — select objects based on attribute values
- Pass to functions — objects can be passed as arguments
Tips for working with objects:
- Use meaningful variable names — make it clear what the object represents
- Store related objects together — use appropriate collection types
- Use methods for state changes — prefer methods over direct attribute changes
- Check object state — verify before performing operations
Quick Check: How do you access an object's attribute? (Answer: Using dot notation: object.attribute)
Complete Example
Building a Complete System
Let's build a complete example that demonstrates everything we've learned — creating classes, defining attributes and methods, instantiating objects, and working with them in a real-world scenario.
# A Complete Example: Library Management System
class Book:
"""Represents a book in the library"""
def __init__(self, title, author, isbn):
self.title = title
self.author = author
self.isbn = isbn
self.is_borrowed = False
def borrow(self):
if not self.is_borrowed:
self.is_borrowed = True
return f"'{self.title}' has been borrowed"
else:
return f"'{self.title}' is already borrowed"
def return_book(self):
if self.is_borrowed:
self.is_borrowed = False
return f"'{self.title}' has been returned"
else:
return f"'{self.title}' was not borrowed"
def get_info(self):
status = "Borrowed" if self.is_borrowed else "Available"
return f"'{self.title}' by {self.author} - {status}"
class Member:
"""Represents a library member"""
def __init__(self, name, member_id):
self.name = name
self.member_id = member_id
self.borrowed_books = []
def borrow_book(self, book):
if len(self.borrowed_books) >= 3:
return f"{self.name} has reached the borrowing limit"
result = book.borrow()
if "borrowed" in result:
self.borrowed_books.append(book)
return result
def return_book(self, book):
if book in self.borrowed_books:
self.borrowed_books.remove(book)
return book.return_book()
else:
return f"{self.name} did not borrow '{book.title}'"
def get_info(self):
books = [book.title for book in self.borrowed_books]
return f"{self.name} (ID: {self.member_id}) - Borrowed: {books}"
class Library:
"""Represents the library system"""
def __init__(self, name):
self.name = name
self.books = []
self.members = []
def add_book(self, book):
self.books.append(book)
return f"Added '{book.title}' to the library"
def register_member(self, member):
self.members.append(member)
return f"Registered {member.name} as a member"
def find_book(self, title):
for book in self.books:
if book.title.lower() == title.lower():
return book
return None
def find_member(self, name):
for member in self.members:
if member.name.lower() == name.lower():
return member
return None
def display_books(self):
print(f"\nBooks in {self.name}:")
for book in self.books:
print(f" {book.get_info()}")
# === Using the System ===
# Create the library
library = Library("City Library")
# Create books
book1 = Book("The Python Guide", "John Smith", "123-456-7890")
book2 = Book("Data Science 101", "Jane Doe", "098-765-4321")
book3 = Book("Web Development", "Bob Johnson", "111-222-3333")
# Add books to the library
print(library.add_book(book1))
print(library.add_book(book2))
print(library.add_book(book3))
# Create members
member1 = Member("Alice", "M001")
member2 = Member("Bob", "M002")
# Register members
print(library.register_member(member1))
print(library.register_member(member2))
# Display books
library.display_books()
# Borrow books
print("\n--- Borrowing Books ---")
print(member1.borrow_book(book1))
print(member1.borrow_book(book2))
print(member2.borrow_book(book1)) # Already borrowed
# Display updated info
print(f"\n{member1.get_info()}")
print(f"{member2.get_info()}")
# Return a book
print("\n--- Returning Books ---")
print(member1.return_book(book1))
# Final status
print(f"\n{member1.get_info()}")
library.display_books()
This complete example demonstrates:
- Three classes — Book, Member, and Library
- Attributes — title, author, is_borrowed, name, borrowed_books
- Methods — borrow, return_book, get_info, register_member
- Instantiation — creating objects from all three classes
- Object interaction — members borrow books from the library
- Data management — tracking what's borrowed and available
What this example teaches:
- Encapsulation — each class manages its own data
- Separation of concerns — each class has a specific role
- Object collaboration — objects work together
- Real-world modeling — code mirrors how a library works
Quick Check: How many classes are in the complete example? (Answer: Three — Book, Member, and Library)
Try It Yourself
Experiment with creating classes and objects in the editor below.
CREATING CLASS AND OBJECT PRACTICE
========================================
1. DEFINING A CLASS
2. CREATING OBJECTS
3. USING METHODS
Alice is working as a Developer
Bob is working as a Designer
4. MODIFYING ATTRIBUTES
Alice got a raise of $5000. New salary: $80000
Alice has been at Tech Corp for 1 years
5. ACCESSING ATTRIBUTES
Alice's salary: $80000
Bob's position: Designer
6. MULTIPLE OBJECTS
Charlie - Manager, $85000, Tech Corp
Diana - Analyst, $70000, Tech Corp
Creating class and object practice complete!
You've Got It!
You now know how to create classes and objects in Python. You understand the syntax, the __init__ method, attributes, methods, and how to instantiate and work with objects.
Quick Quiz
Test what you've learned:
Frequently Asked Questions
What is the difference between a class and an object?
Can I create multiple objects from one class?
What is the self parameter?
self parameter refers to the current instance of the class. It's used to access attributes and methods of the object. When you call a method on an object, Python automatically passes the object as the first argument (self).
What's a common interview question about creating classes?
What naming convention should I use for classes?
MyClass, BankAccount, CustomerProfile. This is the standard convention in Python.
Can I add attributes to an object after creation?
object.new_attribute = value. However, this is generally not recommended as it can make your code harder to understand. It's better to define all attributes in the __init__ method.
Where to Go From Here
Now that you can create classes and objects, check out these related topics:
OOP vs Procedural Programming
Understand the differences between OOP and procedural programming.
Learn More →Difference Between Classes and Objects
Deep dive into the differences between classes and objects.
Learn More →Constructors
Learn more about constructors and their advanced usage.
Learn More →