Introduction
A class is a blueprint that defines the attributes and methods an object will have. An object (also called an instance) is a concrete realization of that blueprint, with its own specific values for those attributes. If Car is a class describing what any car looks like in code, then my_tesla = Car("Tesla", "Model 3") is an object — one particular car built from that blueprint. Understanding the distinction between the blueprint and its instances is the starting point for everything else in OOP.
Cricket analogy: A bat manufacturer's design spec is the class; the actual Kookaburra bat Virat Kohli swings at the crease is the object built from that spec with its own scuffs and grip tape.
Explanation
In Python, classes are defined with the class keyword, and objects are created by calling the class like a function, e.g., Car("Tesla", "Model 3"). The special method __init__ is the constructor: Python calls it automatically right after a new object is created, and its job is to initialize that object's starting state. Attributes defined inside __init__ using self.attribute_name = value are instance attributes — each object gets its own independent copy. Attributes defined directly inside the class body, outside any method, are class attributes — they are shared across all instances of the class unless an instance explicitly overrides them. This distinction matters: mutating a class attribute affects every instance, while mutating an instance attribute affects only that one object.
Cricket analogy: When a new player joins a franchise, the team's constructor process (medical checks, kit fitting, squad number assignment) runs once to set up that player's initial state, just like __init__ initializes an object.
Example
class Car:
# Class attribute: shared by every instance unless overridden
wheels = 4
def __init__(self, make, model, mileage=0):
# Instance attributes: unique to each object
self.make = make
self.model = model
self.mileage = mileage
def drive(self, miles):
self.mileage += miles
def __repr__(self):
return f"Car({self.make!r}, {self.model!r}, mileage={self.mileage})"
car_a = Car("Tesla", "Model 3")
car_b = Car("Toyota", "Corolla", mileage=1200)
car_a.drive(50)
print(car_a) # Car('Tesla', 'Model 3', mileage=50)
print(car_b) # Car('Toyota', 'Corolla', mileage=1200)
print(car_a.wheels) # 4 -- shared class attribute
print(Car.wheels) # 4 -- accessible directly on the class tooAnalysis
car_a and car_b are both instances of Car, but each has its own independent make, model, and mileage because these are set via self. inside __init__. Calling car_a.drive(50) only changes car_a.mileage; car_b.mileage is untouched, proving that instance attributes are per-object. In contrast, wheels is a class attribute defined once in the class body — both car_a.wheels and Car.wheels resolve to the same shared value of 4. If code executed Car.wheels = 6, every instance without its own wheels override would immediately see 6. This example also shows __init__ acting purely as an initializer that runs once at creation time, and __repr__ as a convenience method for readable debugging output, distinct from the core constructor logic.
Cricket analogy: Two openers, Rohit and Gill, each accumulate their own separate run tally during an innings; Rohit hitting a boundary only updates his own score, not Gill's, but both share the team's fixed 11-fielder rule.
Key Takeaways
- A class is a blueprint; an object is a specific instance created from that blueprint.
__init__is the constructor, automatically called when a new object is created.- Instance attributes (
self.x = ...) are unique to each object. - Class attributes (defined in the class body) are shared across all instances unless overridden.
Practice what you learned
1. What is the primary role of `__init__` in a Python class?
2. In the example, why does calling `car_a.drive(50)` not affect `car_b.mileage`?
3. What happens if you set `Car.wheels = 6` after the class is defined?
4. Which of these correctly creates an object of the `Car` class shown in the example?
Was this page helpful?
You May Also Like
OOP Core Concepts
An introduction to the four pillars of object-oriented programming: encapsulation, abstraction, inheritance, and polymorphism.
Encapsulation
How Python conventions for protected and private attributes, plus properties, let classes control access to their internal state.
Inheritance
How single inheritance, `super().__init__()`, and method overriding let subclasses reuse and specialize parent class behavior.
Code Quality and Refactoring
Learn how to measure code quality and use refactoring to improve internal structure without changing external behavior.
Related Reading
Related Study Notes in Software Engineering
Browse all study notesMicroservices Study Notes
Software Architecture · 30 topics
Software EngineeringTesting & TDD Study Notes
Software Testing · 30 topics
Software EngineeringDesign Patterns Study Notes
Software Design · 30 topics
Software EngineeringGit & Version Control Study Notes
Bash · 40 topics
Software EngineeringSystem Design Study Notes
Architecture · 40 topics