Learn What Classes Are in Python: Absolute Beginners Tutorial

A Python class is a blueprint for creating objects. Once you understand how classes work, a large portion of Python's standard library and every third-party package you install will start making sense. This tutorial walks through everything a beginner needs: what a class is, how to write one, what __init__ and self actually do, and how to create and use instances.

Before Python had classes, programs were written as sequences of functions passing data around. That works for small scripts, but as programs grow it becomes hard to keep related data and behavior together. Classes solve that problem by letting you group both in one place.

What Is a Class?

Think of a class as a cookie cutter and instances as the cookies. The cookie cutter defines the shape, but it is not a cookie itself. Every time you use it, you get a new cookie with the same shape but potentially different toppings. In Python terms, the class defines the structure and behavior, and each instance is a separate object that follows that structure while holding its own data.

The Python documentation describes a class as providing a mechanism for bundling data and functionality together. A new class creates a new type of object, allowing new instances of that type to be made. The simplest possible class you can write looks like this:

python
class Dog:
    pass

That is a valid class. The pass keyword tells Python to do nothing — it is a placeholder when the body would otherwise be empty. This class has no attributes and no methods, but Python has registered it as a type you can create objects from.

Note

Python class names use PascalCase by convention: every word is capitalized with no underscores. Dog, BankAccount, and HttpClient are all valid class names. Functions and variables use snake_case by contrast.

What Is an Instance?

An instance is a specific object created from a class. You create one by calling the class like a function:

python
class Dog:
    pass

rex = Dog()
buddy = Dog()

print(type(rex))    # <class '__main__.Dog'>
print(rex is buddy) # False — two separate objects

rex and buddy are both instances of Dog. They are different objects in memory, meaning changes to one do not affect the other. The type() call confirms that rex is a Dog.

code builder click a token to place it

Build the correct statement to define a Python class named Cat:

your code will appear here...
def Cat class = : cat
Why: A class definition starts with the class keyword (not def, which is for functions). The class name follows in PascalCase — so Cat not cat. A colon ends the line, just like if statements and function definitions. The = sign is not used here.

Anatomy of a Python Class

A real class does more than just exist — it holds data and behavior. The three elements you will see in almost every class are the __init__ method, instance attributes assigned through self, and additional methods that define what the object can do.

python
class Dog:
    """A simple class representing a dog."""

    def __init__(self, name, age):
        self.name = name   # instance attribute
        self.age  = age    # instance attribute

    def bark(self):
        print(f"{self.name} says: woof!")

    def describe(self):
        print(f"{self.name} is {self.age} year(s) old.")


rex = Dog("Rex", 4)
rex.bark()      # Rex says: woof!
rex.describe()  # Rex is 4 year(s) old.

What __init__ Does

__init__ is the initializer method. Python calls it automatically the moment you create a new instance. It is not a constructor in the strict sense (Python uses __new__ for that), but for beginners it acts like one: it sets up the instance's starting state. The double underscores on both sides of the name indicate it is a special method that Python knows about and calls at a specific moment.

Pro Tip

Methods whose names start and end with double underscores are called dunder methods (short for double underscore). Python defines many of them: __str__, __repr__, __len__, and others. You will learn them gradually as you write more classes.

What self Does

Every method in a class receives the current instance as its first argument. By convention that argument is named self. When you write rex.bark(), Python translates that call internally to Dog.bark(rex) — it passes rex as self. Inside bark, self.name therefore refers to rex.name.

You must include self as the first parameter in every instance method signature, but you never pass it explicitly when calling the method. Python handles that automatically.

"Classes provide a means of bundling data and functionality together." — Python Software Foundation, Python 3 Tutorial
spot the bug click the line that contains the bug

The class below has one bug. Click the line you think is wrong, then hit check.

1 class Car:
2 def __init__(self, make, year):
3 make = make
4 self.year = year
5 def describe(self):
6 print(f"{self.make} ({self.year})")
Fix: Line 3 should be self.make = make. Without self., the assignment creates a local variable named make that disappears when __init__ returns. The instance never gains a make attribute, so line 6's self.make raises an AttributeError.

Class Attributes vs Instance Attributes

Python distinguishes between two kinds of attributes. Understanding the difference prevents a common category of beginner bugs.

An instance attribute is attached to a specific instance. You create it inside a method by assigning to self.something. Each instance has its own copy.

A class attribute is defined directly in the class body, outside any method. It is shared across all instances unless an instance overrides it with its own value of the same name.

python
class Dog:
    species = "Canis lupus familiaris"  # class attribute — shared

    def __init__(self, name):
        self.name = name  # instance attribute — unique per object


rex   = Dog("Rex")
buddy = Dog("Buddy")

print(rex.species)    # Canis lupus familiaris
print(buddy.species)  # Canis lupus familiaris — same value
print(rex.name)       # Rex
print(buddy.name)     # Buddy — different values

Modifying a class attribute through the class itself affects all instances that have not overridden it. Modifying it through an instance creates a new instance attribute that shadows the class attribute for that instance only.

Watch Out

Using a mutable object (a list or dictionary) as a class attribute is a common bug source. All instances share the same list, so appending to it from one instance affects all others. Use instance attributes (assigned in __init__) for any mutable per-instance data.

Where defined
Inside a method, using self.attr = value
Scope
Unique to each instance — changing it on one object does not affect others
Where defined
Directly in the class body, outside any method
Scope
Shared across all instances unless shadowed by an instance attribute of the same name
Where defined
Inside the class body using def method_name(self, ...):
Scope
Available on all instances; called with dot notation, e.g. my_obj.method()

How to Write a Python Class

Follow these steps every time you need to define a new class from scratch. The pattern applies whether you are modeling a dog, a user account, or a network packet.

  1. Declare the class

    Use the class keyword followed by a PascalCase name and a colon. Add a docstring on the next indented line to describe what the class represents. Example: class BankAccount:

  2. Define __init__

    Inside the class, write def __init__(self, ...): with whatever parameters the object needs at creation time. Assign each one to self.attribute_name so it is saved on the instance. Example: self.balance = initial_balance

  3. Add methods

    Define additional methods inside the class body. Each must take self as its first parameter. Use self.attribute to read or update instance data. Example: def deposit(self, amount): self.balance += amount

  4. Create instances

    Outside the class definition, call the class like a function and assign the result to a variable. Pass any arguments that __init__ expects (except self). Example: account = BankAccount(500)

  5. Access attributes and call methods

    Use dot notation to read attributes and call methods on the instance. Example: print(account.balance) reads the attribute; account.deposit(100) calls the method and updates the balance.

Putting it all together, a complete BankAccount class looks like this:

python
class BankAccount:
    """Represents a simple bank account."""

    def __init__(self, owner, initial_balance=0):
        self.owner   = owner
        self.balance = initial_balance

    def deposit(self, amount):
        self.balance += amount
        print(f"Deposited {amount}. New balance: {self.balance}")

    def withdraw(self, amount):
        if amount > self.balance:
            print("Insufficient funds.")
        else:
            self.balance -= amount
            print(f"Withdrew {amount}. New balance: {self.balance}")

    def show_balance(self):
        print(f"{self.owner}'s balance: {self.balance}")


account = BankAccount("Alice", 200)
account.deposit(50)       # Deposited 50. New balance: 250
account.withdraw(300)     # Insufficient funds.
account.show_balance()    # Alice's balance: 250

Python Classes: Key Learning Points

  1. A class is defined with the class keyword and a PascalCase name. It is a blueprint, not an object itself.
  2. __init__ runs automatically when you create an instance and is where you set up instance attributes using self.
  3. self is always the first parameter of an instance method and refers to the calling instance. You never pass it manually — Python does.
  4. Instance attributes (set with self.attr) belong to one object. Class attributes (set in the class body) are shared by all instances.
  5. You access attributes and call methods using dot notation: obj.attribute and obj.method().

Classes are the foundation of object-oriented programming in Python. Once you are comfortable with what is covered here — defining a class, writing __init__, using self, and creating instances — you are ready to move on to inheritance, where one class can build on another.

check your understanding question 1 of 5

Frequently Asked Questions

A class in Python is a blueprint for creating objects. It defines a set of attributes (data) and methods (functions) that every object created from that class will have. You define a class using the class keyword followed by the class name and a colon.

A class is the template or blueprint, while an instance is a specific object created from that template. You can create many instances from one class, and each instance holds its own data while sharing the class's methods.

__init__ is the initializer method that Python calls automatically when you create a new instance of a class. It sets up the instance's starting data (attributes). The double underscores indicate it is a special method built into Python's object system.

self is a reference to the current instance of the class. When you call a method on an object, Python automatically passes that object as the first argument. By convention, this parameter is always named self, though technically any name works.

A class attribute is defined directly on the class and is shared by all instances. An instance attribute is defined inside a method (typically __init__) using self, and each instance has its own separate copy of it.

No. __init__ is optional. If you do not define it, Python uses a default one that does nothing. You only need __init__ when your instances need starting data set up at creation time.

You create an object by calling the class like a function. For example, if your class is named Dog, you write my_dog = Dog('Rex', 3) to create a new instance. Python automatically calls __init__ with the arguments you provide.

A method is a function defined inside a class. Methods always take self as their first parameter so they can access and modify the instance's data. You call a method on an instance using dot notation, for example my_dog.bark().

Yes. A class can have as many methods as needed. Each method is a function defined inside the class body, and each one receives self as its first parameter to access the instance.

Dot notation is how you access attributes and call methods on an object. The dot connects the object name to the attribute or method name. For example, my_dog.name accesses the name attribute, and my_dog.bark() calls the bark method.