Free demoJob-oriented courses at Debugshala, Old Palasia, Indore. Freshers, non-IT and year-gap welcome.Book a free demo +91-8982385539

Python Classes and Objects: __init__, self, Attributes, Methods

Lesson 39 of 52 · 8 min · Updated 13 Nov 2026

Learn Python classes and objects: the class keyword, __init__ and self, instance vs class attributes, methods, __repr__ and classmethod, with sales examples.

Picture a builder putting up a housing township on the Super Corridor in Indore. The architect draws one floor plan for a 2BHK flat: two bedrooms, a kitchen, a balcony facing east. That single drawing is used to build 120 flats.

Each flat is built from the same plan, yet each is separate. Flat 304 has blue walls and the Sharma family. Flat 512 has white walls and a home office. Painting one flat does not change any other, and nobody lives in the drawing itself.

In Python, the floor plan is a class. Each flat is an object (also called an instance). The wall colour and the family are the object's attributes, and things you can do in a flat, like "switch on the geyser", are its methods.

A class in Python is a blueprint, defined with the class keyword, that describes the attributes and methods its objects will have; an object is a single instance created from that class, with its own copy of the instance data.

This lesson opens the OOP section, after Python custom exceptions, where you already wrote small classes without knowing it. Examples target Python 3.12+.

What is a class and an object in Python?

You have used objects since your first program. Every value in Python is an object, and every object has a class. The number 5 is an instance of int, and a pandas DataFrame is an instance of the DataFrame class.

Python
import pandas as pd

values = [5, "Indore", [1450, 980], {"city": "Ujjain"}]
for v in values:
    print(repr(v), "is an instance of", type(v).__name__)

df = pd.DataFrame({"store": ["Palasia", "Rajwada"], "sales": [48200, 39100]})
print(type(df).__name__, "with", len(df), "rows")
print("upper() is a method of str:", "indore".upper())

When you call df.head() or "indore".upper(), you are calling a method that the class defined. Writing your own class lets you create the same kind of thing for your own data: a store, an invoice, a sales target.

How do you create a class in Python?

You write class, a name in CapitalisedWords, and an indented body. Inside, the special method __init__ runs automatically each time you create an object. It receives the new, empty object as self and fills in its attributes.

Python
class Store:
    def __init__(self, name, monthly_target):
        self.name = name
        self.monthly_target = monthly_target
        self.sales = []                    # each store gets its own list

palasia = Store("Palasia", 50000)
rajwada = Store("Rajwada", 35000)

palasia.sales.append(12500)
print(palasia.name, palasia.monthly_target, palasia.sales)
print(rajwada.name, rajwada.monthly_target, rajwada.sales)
print(palasia is rajwada)

Store("Palasia", 50000) does two things. Python first creates a blank Store object, then calls __init__(that_object, "Palasia", 50000). Inside __init__, self.name = name attaches an attribute to that particular object. The finished object is returned and stored in palasia.

Python class and objects: one Store class blueprint creates separate palasia and rajwada objects, each with its own name, target and sales attributes

One class, many objects: each object keeps its own copy of the instance attributes.

What is self in Python?

self is simply the first parameter of every regular method, and it refers to the object the method was called on. When you write palasia.record_sale(1200), Python turns it into Store.record_sale(palasia, 1200). The name self is a convention, not a keyword, but always use it.

Quick check

What does self refer to inside an instance method?

Adding methods to a class

A method is a function defined inside a class. Because it receives self, it can read and change that object's attributes. This is the real point of classes: the data and the code that works on it live together.

Python
class Store:
    def __init__(self, name, monthly_target):
        self.name = name
        self.monthly_target = monthly_target
        self.sales = []

    def record_sale(self, amount):
        if amount <= 0:
            raise ValueError("amount must be positive")
        self.sales.append(amount)

    def progress(self):
        return round(sum(self.sales) / self.monthly_target * 100, 1)

palasia = Store("Palasia", 50000)
for amount in [12500, 8400, 15100]:
    palasia.record_sale(amount)
print(f"{palasia.name}: {sum(palasia.sales)} sold, {palasia.progress()}% of target")
print(Store.progress(palasia))     # the same call, written the long way

Notice that record_sale checks its input before changing anything. Guarding an object's data inside its own methods keeps every store consistent, wherever in the program it is used.

Instance attributes vs class attributes

An attribute set on self is an instance attribute, unique to one object. An attribute written directly in the class body is a class attribute, shared by every object. Use class attributes for constants and for values that are truly the same for all instances.

Python
class Store:
    gst_rate = 0.18                 # class attribute: shared
    count = 0

    def __init__(self, name):
        self.name = name            # instance attribute: per object
        Store.count += 1

a, b = Store("Palasia"), Store("Rajwada")
print(a.gst_rate, b.gst_rate, Store.count)

a.gst_rate = 0.05                   # creates an instance attribute on a only
print(a.gst_rate, b.gst_rate, Store.gst_rate)
print("a's own attributes:", vars(a))
print("b's own attributes:", vars(b))

When you read a.gst_rate, Python looks in the object's own attributes first and then in the class. Assigning a.gst_rate = 0.05 does not change the class; it creates a new instance attribute that shadows the shared one, for a only.

Python attribute lookup: reading obj.attribute checks the instance dictionary first, then the class, then raises AttributeError

Attribute lookup goes from the object to its class. Assignment through an object always writes to the object.

Quick check

A class has gst_rate = 0.18 as a class attribute. After a.gst_rate = 0.05, what is b.gst_rate for another instance b?

Printing objects with __repr__

By default, printing an object shows something like <__main__.Store object at 0x7f...>, which is useless in a report. Define __repr__ to return a clear text form. Methods with double underscores, called dunder methods, are covered in depth in Python operator overloading.

Python
class Store:
    def __init__(self, name, city, target):
        self.name, self.city, self.target = name, city, target

    def __repr__(self):
        return f"Store(name={self.name!r}, city={self.city!r}, target={self.target})"

    @classmethod
    def from_csv_line(cls, line):
        name, city, target = line.split(",")
        return cls(name.strip(), city.strip(), int(target))

stores = [Store.from_csv_line(l) for l in ["Palasia, Indore, 50000", "Freeganj, Ujjain, 22000"]]
print(stores)
print(stores[1])

The @classmethod above is an alternative constructor. It receives the class as cls instead of an object, so it can build a new instance from a different input format, here a CSV line.

Method type First parameter Typical use
Instance method self (the object) Read or change one object's data
@classmethod cls (the class) Alternative constructors like from_csv_line
@staticmethod none A helper that belongs with the class but uses neither

When should a data analyst write a class?

Not every script needs one. A list of Python dictionaries and a few functions is often clearer. Reach for a class when the same group of data keeps travelling with the same operations, or when you need many objects that each track their own state.

Good signs: you pass the same four arguments to five functions, or you keep checking the same rules on dict keys. A Store, Invoice or Campaign class puts those rules in one place. For classes that mostly hold data, Python dataclasses remove most of the boilerplate.

Common mistakes with Python classes

  • Forgetting self in a method definition. def progress(): fails with a TypeError when called on an object.
  • Writing name = name instead of self.name = name. The value is stored in a local variable and lost.
  • Mutable class attributes. sales = [] in the class body is one list shared by all objects. Create lists in __init__.
  • Calling the method without brackets. store.progress is the method itself; store.progress() runs it.
  • Changing a class attribute through an object. a.count += 1 creates an instance attribute. Use Store.count.
  • A class for everything. If it has one method and no state, a plain function is better.

Key takeaways

  • A class is a blueprint; an object is one instance built from it.
  • __init__ runs on creation and sets instance attributes on self.
  • Methods are functions in the class that receive the object as self.
  • Class attributes are shared; instance attributes belong to one object.
  • Lookup checks the object first, then the class.
  • Define __repr__ so objects print clearly, and use @classmethod for alternative constructors.

Next, reuse a class's code in another class with Python inheritance. Turning messy spreadsheet logic into small, testable classes is practised in the classroom data analytics programme taught in English and Hindi at Debugshala.

Take the free Python Programming quiz10 quick questions with explanations. No sign-up needed, and you can come back to this lesson after.

FAQ

What is the difference between a class and an object in Python?

A class is the definition, like a blueprint, that says which attributes and methods its objects have. An object is a concrete instance made from that class, holding its own data. Store is a class; Store("Palasia", 50000) creates an object. One class can produce any number of independent objects.

Why is self used in Python classes?

self gives a method access to the specific object it was called on, so it can read and change that object's attributes. Python passes it automatically: store.progress() becomes Store.progress(store). The name is a strong convention rather than a keyword, so other names work but confuse readers.

Is __init__ a constructor in Python?

It is usually called the constructor, though strictly it is an initialiser. Python creates the empty object first using __new__, then calls __init__ to fill in its attributes. You rarely need __new__. Put all your setup, such as storing arguments and creating empty lists, inside __init__.

Do data analysts need object-oriented programming?

You can do a lot of analysis with functions and pandas alone, but you use objects constantly, since DataFrames, Series and models are all classes. Knowing OOP helps you read library documentation, organise larger scripts and pass coding interviews, where classes are a standard topic.

Where can I learn Python OOP in Indore?

Debugshala teaches Python, including classes and objects, as part of its data analytics course at the Old Palasia campus in Indore. Classes are in English and Hindi, fresh graduates and non-IT learners are welcome, and there is a free demo class. You can also test your class and object basics on Debugshala Test.

From the team behind this site

Go further with the Data Analytics Course at Debugshala

These tutorials are written by Debugshala, a training and placement institute at Old Palasia, Indore. The classroom course adds live mentoring, real projects and interview preparation.

  • Offline classes at Old Palasia, Indore
  • Free demo class before you pay
  • Non-IT, fresher and year-gap friendly
  • Placement assistance

700+ students placed · 200+ hiring partners · 4.9★ Google rating

Python Custom Exceptions: Create Your Own Exception ClassesPython Inheritance: Parent and Child Classes, super() and MRO