Classes

Python - A Quick Start for existing Programers

3 min read

Published Sep 16 2025, updated Aug 17 2026


21
0
0
0

Python

Python supports OOP and classes:

  • Defined by the class keyword.
  • Structure is indented.
  • Top level variables are class attributes available on all instances of a class.
  • Constructer is defined as a function with the name __init__(self, ...).
    • Self object is used to set instance variables: self.my_instance_variable = 4.
    • Constructer parameters can be passed in to the init function: __init__(self, my_parameter1).
    • Inside the init function set self.my_instance_variable = my_parameter1 to set instance variables.
  • Top level functions are instance functions by default and can access self.

Example:

class Dog:    """ Doc string (multi-line comment) to define what the class does, shows up in intellisense in IDE """​    # Class attribute (shared by all dogs)    species = "Canis familiaris"​    # Constructor (initializer)    def __init__(self, name, age):        # instance attributes        self.name = name            self.age = age​    # Instance method    def bark(self):        return f"{self.name} says Woof!"​# Create objects (instances)dog1 = Dog("Rocky", 5)dog2 = Dog("Luna", 3)​print(dog1.name)# Rockyprint(dog1.age)# 5print(dog1.species)# Canis familiarisprint(dog1.bark())   # Rocky says Woof!​print(dog2.name)# Lunaprint(dog2.age)# 3print(dog2.species)# Canis familiarisprint(dog2.bark())   # Luna says Woof!​print(Dog.species)# Canis familiaris




Class methods

Instance Method (default):

  • Normal methods in a class.
  • Take self as the first argument.
  • Can access instance attributes and class attributes.
  • Is called on an individual instance of a class.
class Demo:    def instance_method(self):        return f"Called instance_method on {self}"


Class Method (@classmethod):

  • Declared with @classmethod decorator.
  • First parameter is cls (the class itself, not an instance).
  • Can access/modify class attributes but not instance attributes (unless given an instance).
  • Often used as factory methods (alternate constructors).
  • Is called on the actual class record.
class Demo:    counter = 0​    def __init__(self, value):        self.value = value        Demo.counter += 1​    @classmethod    def how_many(cls):           # cls refers to the class        return f"There are {cls.counter} instances."​    @classmethod    def from_string(cls, value_str):           # factory method        return cls(int(value_str))​a = Demo(10)b = Demo.from_string("20")  # create instance from stringprint(Demo.how_many())      # "There are 2 instances."

Static Method (@staticmethod):

  • Declared with @staticmethod decorator.
  • No self or cls parameter → acts like a regular function, but lives inside the class for organisation.
  • Cannot access class or instance attributes (unless passed explicitly).
  • Used for utility/helper functions related to the class.
  • Is called on the actual class record.
class MathHelper:    @staticmethod    def add(a, b):        return a + b​print(MathHelper.add(5, 7))  # 12

Dunder methods:

  • Special methods denoted with __ __ either side.
  • Has special purposes, such as the __init__ function.
  • See section below for more details.



Encapsulation (Attribute Access)

There is no true private attribute enforcement like in other languages, Instead a naming convention using _ and __ is used.


Public (no underscore):

  • Normal attributes are fully accessible.
class Demo:    def __init__(self):        self.value = 42​obj = Demo()print(obj.value)  # Works fine


Protected (_single):

  • Just a convention: “for internal use, but you can access it if you really want.”
class Demo:    def __init__(self):        self._internal = "protected-ish"​obj = Demo()print(obj._internal)  # Works, but convention says "don’t"

Private (__double):

  • Triggers name mangling: Python renames it to _ClassName__attr.
  • Makes accidental access harder, but still accessible if you know the mangled name.
class Demo:    def __init__(self):        self.__secret = "hidden"​obj = Demo()​# print(obj.__secret)  # AttributeError​print(obj._Demo__secret)  # Works as its manually using the mangled name, but not recommended




Inheritance

Inheritance is supported in Python classes, allowing you to use inherited attributes and methods and override methods.

class Animal:    def __init__(self, name):        self.name = name​    def speak(self):        return "..."​class Dog(Animal):    def speak(self):        return "Woof!"​dog = Dog("Rex")​print(dog.name)    # Inherited from Animal​print(dog.speak()) # Overridden in Dog

The super() function

  • Calls methods of the parent class.
  • Commonly used in __init__ to ensure parent initialisation runs, see highlighted row in the example below where it calls the parents constructor first to initialise the common attributes and then sets the class specific attributes.
  • Avoids hardcoding the parent class name → important in multiple inheritance.
class Animal:    def __init__(self, name):        self.name = name​class Dog(Animal):    def __init__(self, name, breed):        # Call parent constructor        super().__init__(name)        self.breed = breed​dog = Dog("Rex", "Labrador")​print(dog.name)   # from Animal​print(dog.breed)  # from Dog

Example: Calling parent methods:

class Animal:    def speak(self):        return "Some sound"​class Cat(Animal):    def speak(self):        # Use parent method, then extend        base_sound = super().speak()        return base_sound + " Meow!"​cat = Cat()​print(cat.speak())  # "Some sound Meow!"

Multiple Inheritance and super()

Python supports multiple inheritance. super() follows the MRO (Method Resolution Order).

class A:    def greet(self):        print("Hello from A")​class B(A):    def greet(self):        print("Hello from B")        super().greet()​class C(A):    def greet(self):        print("Hello from C")        super().greet()​class D(B, C):    def greet(self):        print("Hello from D")        super().greet()​d = D()d.greet()​# Output:# Hello from D# Hello from B# Hello from C# Hello from A




Dunder methods

Python has a lot of dunder (double underscore) methods, also called magic methods. They let your objects integrate seamlessly with Python’s built-in syntax and functions.

  • Dunder methods = special hooks that let your class behave like built-in types.
  • This allows you to be able to dfine how you class works with the len method, or how it will print when doing an f sting etc.
  • Categories:
    • Initialisation (__init__, __str__, __repr__)
    • Attribute access (__getattr__, __setattr__)
    • Callable/context (__call__, __enter__, __exit__)
    • Comparisons (__eq__, __lt__, etc.)
    • Containers (__len__, __getitem__, etc.)
    • Operators (arithmetic, bitwise, in-place, reflected)
    • Misc (__bool__, __index__, async methods)

Examples:

class MyCollection:    def __init__(self, items):        self.items = list(items)​    # String representation    def __str__(self):        return f"MyCollection({self.items})"​    def __repr__(self):        return f"MyCollection({self.items!r})"​    # Length    def __len__(self):        return len(self.items)​    # Indexing / slicing    def __getitem__(self, index):        return self.items[index]​    def __setitem__(self, index, value):        self.items[index] = value​    def __delitem__(self, index):        del self.items[index]​    # Iteration    def __iter__(self):        return iter(self.items)​    # Membership test    def __contains__(self, item):        return item in self.items​    # Addition (combine two collections)    def __add__(self, other):        return MyCollection(self.items + other.items)​    # Equality    def __eq__(self, other):        return self.items == other.items​    # Boolean    def __bool__(self):        return bool(self.items)​    # Callable    def __call__(self):        print("This collection has", len(self), "items!")​# ------------------------------------# Usage# ------------------------------------​col1 = MyCollection([1, 2, 3])col2 = MyCollection([4, 5])​# __str__print("String:", col1)               ​# __repr__print("Representation:", repr(col1)) ​# __len__print("Length:", len(col1))          ​# __getitem__print("Indexing:", col1[1])     ​# __setitem__col1[1] = 20                          print("After setitem:", col1)​# __delitem__del col1[0]                           print("After delitem:", col1)​# __iter__print("Iteration:", [x for x in col1]) ​# __contains__print("Membership 20 in col1?", 20 in col1) ​# __add__col3 = col1 + col2                     print("Addition:", col3)​# __eq__print("Equality col1==col3?", col1 == col3) ​# __bool__print("Boolean col1?", bool(col1))          ​# __call__col1()




Full demonstration of classes

# Base classclass Animal:    # Class attribute    species = "Generic Animal"   ​    def __init__(self, name, age):        # Instance attributes        self.name = name              self.age = age​    def speak(self):                     # Instance method        return "Some generic sound"​    @classmethod    def class_info(cls):                 # Class method        return f"This is the {cls.__name__} class."​    @staticmethod    def kingdom():                       # Static method        return "Animalia"​    def __str__(self):                   # String representation        return f"{self.name} ({self.age} yrs)"​# Derived class (inheritance)class Dog(Animal):    species = "Canis familiaris"​    def speak(self):                     # Override parent method        return f"{self.name} says Woof!"​# Another derived classclass Cat(Animal):    species = "Felis catus"​    def speak(self):                     # Override parent method        return f"{self.name} says Meow!"​# Custom class with operator overloadingclass Point:    def __init__(self, x, y):        self.x, self.y = x, y​    def __add__(self, other):            # Overload +        return Point(self.x + other.x, self.y + other.y)​    def __str__(self):        return f"({self.x}, {self.y})"​# ------------------------------------# Usage# ------------------------------------​# Create objectsdog = Dog("Buddy", 5)cat = Cat("Lucy", 3)​print("Dog:", dog)print("Cat:", cat)print("Dog speaks:", dog.speak())print("Cat speaks:", cat.speak())​# Class method and static methodprint("Class method:", Dog.class_info())print("Static method:", Animal.kingdom())​# Inheritance in actionanimals = [dog, cat, Animal("Generic", 1)]for a in animals:    print(f"{a.name} is a {a.species} and says: {a.speak()}")​# Operator overloadingp1, p2 = Point(1, 2), Point(3, 4)print("Points:", p1, "+", p2, "=", p1 + p2)
© 2025 SimpleSteps.guide
AboutFAQPoliciesContact