• Home
  • LLMs
  • Python
  • Docker
  • Kubernetes
  • Java
  • Maven
  • All
  • About
Python | Object-Oriented Programming: Classes
Basic class definition:
Classes are blueprints for creating objects in Python.
They bundle data (attributes) and behavior (methods), enabling object-oriented programming concepts like encapsulation, inheritance, and polymorphism.

  • Defining a class:
    __init__: this constructor method is called automatically when an instance of the class is created.
    self: is a reference to the current instance. It is automatically passed to methods.
    Instance variables: they are variables defined with self and are accessible to all methods in the class and to all instances of the class.

    class Math:
      # class variable (shared by all instances)
      name = 'Simple Math'
    
      def __init__(self, i, j):
        # instance variables
        self.i = i
        self.j = j
    
      def set_i(self, i):
        self.i = i
    
      def set_j(self, j):
        self.j = j
    
      def add(self):
        return self.i + self.j
    
      def multiply(self):
        return self.i * self.j
    
      @classmethod
      def get_name(cls):
        return cls.name
    
      @staticmethod
      def validate_name(name):
        return isinstance(name, str)
    
      # string representation (if not defined, __repr__ is used)
      def __str__(self):
        return f"Math({self.i}, {self.j})"
    
      # developer representation (also used as string representation if __str__ is not defined)
      def __repr__(self):
        return f"Math(i={self.i}, j={self.j})"
  • Creating an instance:
    math1 = Math(2, 3)
  • Calling methods:
    print(math1.add()) # Output: 5
    print(math1.multiply()) # Output: 6
  • Accessing attributes:
    print(math1.i) # Output: 2
    print(math1.j) # Output: 3
  • Modifying attributes:
    math1.i = 3
    math1.set_j(7)
    print(math1.add()) # Output: 10
    print(math1.multiply()) # Output: 21
  • String representation
    # string representation
    print(math1) # Output: Math(3, 7)
    
    # developer representation
    print(repr(math1)) # Output: Math(i=3, j=7)
  • Using class/static methods/attributes
    # access class variable
    print(Math.name) # Output: Simple Math
    
    # access class method
    print(Math.get_name()) # Output: Simple Math
    
    # access static method
    print(Math.validate_name("Math")) # Output: True
Property decorators:
class Audit:
  def __init__(self, msg):
    self._msg = msg

  @property
  def message(self):
    return self._msg

  @message.setter
  def message(self, msg):
    self._msg = msg

audit = Audit('Hello')

# access property
print(audit.message) # Output: Hello

# set property
audit.message = "Python"

print(audit.message) # Output: Python
Inheritance:
Inheritance allows a class to inherit attributes and methods from a parent class.

  • Defining a subclass:
    class Operations(Math):
      def __init__(self, i, j):
        super().__init__(i, j)
        self.code = 'undefined'
    
      # define new method
      def set_code(self, code):
        self.code = code
    
      # define new method
      def calculate(self, code='add'):
        if code == 'add':
          return super().add()
        elif code == 'multiply':
          return super().multiply()
        else:
          return 'Unknown operation'
  • Creating an instance of the subclass:
    operation = Operations(4, 9)
  • Accessing attributes of the subclass:
    print(operation.i) # Output: 4
    print(operation.j) # Output: 9
    print(operation.code) # Output: undefined
  • Calling methods of the subclass:
    # calling parent class method
    print(operation.add()) # Output: 13
    
    # calling subclass methods
    print(operation.calculate()) # Output: 13
    print(operation.calculate('multiply')) # Output: 36
    print(operation.calculate('divide')) # Output: Unknown operation
Method overriding:
Subclasses can override methods from their parent class to provide specialized behavior.

  • Overriding methods from the parent class:
    class SpecialMath(Math):
      def __init__(self, i, j, multiplier=10):
        super().__init__(i, j)
        self.multiplier = multiplier
    
      # override parent method
      def multiply(self):
        return self.i * self.j * self.multiplier
  • Calling override methods of an instance of a subclass:
    specialMath = SpecialMath(4, 6)
    print(specialMath.multiply()) # Output: 240
    
    # custom multiplier
    specialMath = SpecialMath(4, 6, 100)
    print(specialMath.multiply()) # Output: 2400
Modules and imports
  • Creating a module:
    Create a file class_module_1.py that contains the definition of two classes:
    $ vi class_module_1.py
    class MyClassA():
      def __init__(self):
        self.name = 'My Class A'
    
    class MyClassB():
      def __init__(self):
        self.name = 'My Class B'
    
    # Module-level function
    def get_module_file_name():
      return "class_module_1.py"
  • Import entire module:
    Create a file class_import_1.py that imports the module class_module_1 (class_module_1.py):
    $ vi class_import_1.py
    # all classes defined in the module will be accessible using the prefix class_module_1
    import class_module_1
    
    # referencing the classes using the name of the module name as a prefix
    myclassa = class_module_1.MyClassA()
    myclassb = class_module_1.MyClassB()
    
    print(myclassa.name) # Output: My Class A
    print(myclassb.name) # Output: My Class B
    
    # calling module function
    print(class_module_1.get_module_file_name()) # Output: class_module_1.py
  • Import specific classes:
    Create a file class_import_2.py that imports specific classes defined in the module class_module_1 (class_module_1.py):
    $ vi class_import_2.py
    # importing the classes MyClassA and MyClassB from the module class_module_1
    from class_module_1 import MyClassA, MyClassB
    
    # referencing directly the classes without specifying the module name
    myclassa = MyClassA()
    myclassb = MyClassB()
    
    print(myclassa.name) # Output: My Class A
    print(myclassb.name) # Output: My Class B
  • Import all:
    Create a file class_import_3.py that imports all classes defined in the module class_module_1 (class_module_1.py):
    $ vi class_import_3.py
    # importing all public names from the module class_module_1
    from class_module_1 import *
    
    # referencing directly the classes without specifying the module name
    myclassa = MyClassA()
    myclassb = MyClassB()
    
    print(myclassa.name) # Output: My Class A
    print(myclassb.name) # Output: My Class B
    
    # calling module function without prefix
    print(get_module_file_name()) # Output: class_module_1.py
  • Module aliases
    Using the keyword as to define an alias for a module.
    Create a file class_import_4.py that imports the module class_module_1 (class_module_1.py) and give it an alias f1:
    $ vi class_import_4.py
    # defining the alias f1 for the module class_module_1
    import class_module_1 as f1
    
    # referencing the class MyClassA using the alias of the module as a prefix
    myclassa = f1.MyClassA()
    myclassb = f1.MyClassB()
    
    print(myclassa.name) # Output: My Class A
    print(myclassb.name) # Output: My Class B
    
    # calling module function using prefix
    print(f1.get_module_file_name()) # Output: class_module_1.py
  • Class aliases:
    Using the keyword as to define an alias for a class.
    Create a file class_import_5.py that imports specific classes defined in the module class_module_1 (class_module_1.py) and give them aliases:
    $ vi class_import_5.py
    # defining the alias A for the class MyClassA and the alias B for the class MyClassB
    from class_module_1 import MyClassA as A, MyClassB as B
    
    # referencing directly the classes using its alias A
    myclassa = A()
    myclassb = B()
    
    print(myclassa.name) # Output: My Class A
    print(myclassb.name) # Output: My Class B
© 2025  mtitek