Skip to content
Go back

Demystifying Python Classes with Real-World Examples

Python classes let you bundle data and behavior. Think of a class as a blueprint. Just like a recipe tells you how to bake a cake, a class tells Python how to build an object.

When you create a class you define two things: attributes and methods. Attributes hold state. Methods perform actions. Here is a tiny example:

class Counter:
    count = 0

    def __init__(self):
        self.value = 0

    def increment(self):
        self.value += 1
        Counter.count += 1

c1 = Counter()
c2 = Counter()
c1.increment()
c2.increment()
print(Counter.count)   # likely shows 2

I still remember the first time I wrote a class. I felt like I was giving life to a piece of code. The simple act of defining a method made the program feel more organized.

Attributes can be instance specific or shared. In the example above count is a class attribute. It lives on the class itself. Each instance gets its own value attribute. This distinction matters when you work with mutable objects.

class Dog:
    tricks = []          # shared list can be surprising

    def __init__(self, name):
        self.name = name

    def add_trick(self, trick):
        self.tricks.append(trick)

d1 = Dog('Fido')
d2 = Dog('Buddy')
d1.add_trick('roll over')
d2.add_trick('play dead')
print(d1.tricks)       # may contain both tricks

The output may contain both tricks because the list is shared. A safer design uses an instance attribute:

class Dog:
    def __init__(self, name):
        self.name = name
        self.tricks = []   # fresh list for each dog

    def add_trick(self, trick):
        self.tricks.append(trick)

Now each dog keeps its own tricks.

Methods receive the instance as their first argument. Python calls this argument self. The name itself is not magical; it is just a convention. If you ignore the convention your code may be harder for others to read.

class Bag:
    def __init__(self):
        self.data = []

    def add(self, item):
        self.data.append(item)

    def show(self):
        return self.data

bag = Bag()
bag.add('apple')
bag.add('banana')
print(bag.show())        # likely shows ['apple', 'banana']

You can also inherit from a class. Inheritance lets you reuse code and add new behavior. Here is a quick example:

class Animal:
    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        return 'Woof'

class Cat(Animal):
    def speak(self):
        return 'Meow'

for pet in (Dog(), Cat()):
    print(pet.speak())     # likely prints Woof then Meow

Multiple inheritance is possible but can become complex. Python uses a method resolution order to decide which method to call. In most everyday cases you will stick with a single base class.

Private attributes follow a naming convention. A name that starts with an underscore is considered private. Python does not enforce privacy; it just signals intent. Name mangling can be used to avoid accidental overrides:

class Mapping:
    def __init__(self, mapping):
        self.items = []
        self.__update(mapping)

    def update(self, mapping):
        for key, value in mapping.items():
            self.items.append((key, value))

    __update = update   # private copy

class Sub(Mapping):
    def update(self, keys, values):
        for k, v in zip(keys, values):
            self.items.append((k, v))

The mangled name changes to keep the method call intact.

You can also create data‑carrying classes with the dataclass decorator. It reduces boilerplate:

from dataclasses import dataclass

@dataclass
class Employee:
    name: str
    dept: str
    salary: int

e = Employee('Jane', 'Engineering', 90000)
print(e.dept)   # likely shows Engineering
print(e.salary) # likely shows 90000

That’s it for a quick tour of Python classes. The concepts build on each other. Start with a simple class, play with attributes, then explore inheritance and dataclasses. The journey is rewarding and the community is generous with examples.


Tags

Share this post on: