AAtsushi's Blog
Python

Object-Oriented Programming in Python

→ 日本語版を読む

Overview

Microsoft Learn had a nicely organized introduction to object-oriented programming in Python, so I'm taking notes on the overview.

https://learn.microsoft.com/ja-jp/training/modules/python-object-oriented-programming/

Introduction to Object-Oriented Programming with Python

Both object-oriented programming (OOP) and procedural programming execute a series of steps. That is:

  1. Data input
  2. Processing
  3. Data output

The difference lies in how you view the world. In OOP, rather than processing data phase by phase, you grasp the entire world where data is moving and "model" the things you see.

Modeling is done with the following steps:

  1. Identify actors that perform actions
  2. Understand the behavior of actors
  3. Identify the data needed to perform actions
  4. Code the actors as objects
    • Encode characteristics as the object's data
    • Add the actor's behavior to the object as functions

The key idea is that the data of an object is changed by calling functions on that object. Also, objects "interacting with each other" achieves concrete results.

OOP is not necessarily superior to other paradigms; it has both advantages and disadvantages. The advantages of OOP include:

  • Data encapsulation (limiting access to data)
  • Simplicity
  • Ease of modification
  • Maintainability
  • Reusability

Important points to understand in OOP:

  • Basic concepts and relationships such as classes, objects, and state
  • How to handle variables and add variables to objects

An object is an actor — something that performs actions. When an action is performed, the state of the object that performed the action or other objects changes. Objects have properties. For a car, these might be the manufacturer, model, vehicle type, color, etc. A class is a template for an object (you can also call it a blueprint). And objects are created from classes.

Creating an object from a class is called instantiation (= object creation), which is requesting the OS to "give initial values to the class, allocate memory, and create an object."

Objects have attributes (attributes), and attribute values are used to describe the object or maintain the object's state.

Encapsulation

Making internal data of an object inaccessible for direct inspection or preventing data from being modified. In other words, making member variables private. However, in Python, perfect private variables cannot be achieved.

Therefore, there is a convention of prefixing variable names with two underscores (__) to indicate they are private member variables. In practice, even with self.__variable_name, the variable's value can still be manipulated externally.

class Square:
    def __init__(self, val):
          self.__height = val
          self.__width  = val

square = Square(2)
square.__height = 3 # Does not raise AttributeError. Microsoft Learn states it raises AttributeError, but that is incorrect.
print(square.__height) # Displays 3.

However, if you try to reference it directly, you do get an AttributeError.

class Square:
    def __init__(self, val):
          self.__height = val
          self.__width  = val

square = Square(2)
print(square.__height) # Raises AttributeError

Incidentally, using _ClassName__variable_name allows you to access it even then.

class Square:
    def __init__(self, val):
          self.__height = val
          self.__width  = val

square = Square(2)
print(square._Square__height) # Displays 2. No error.

Handling Member Variables

As described above, even private member variables can have their values changed. Therefore, by using getters and setters, you can prevent bad values (unexpected values) from being set.

By attaching the @property decorator to a method, the method can be called without (). This is used to define a method for retrieving values (getter). Using @<property_name>.setter allows you to check for invalid values when setting a value. However, it is better to avoid defining things as properties unnecessarily, as it complicates the code.

class Square:
   def __init__(self, val):
         self.__height = val
         self.__width = val

   def set_side(self, new_side):
         self.__height = new_side
         self.__width = new_side

   @property
   def height(self):
      return self.__height

   @height.setter
   def height(self, new_value):
      if new_value >= 0:
         self.__height = new_value
      else:
         raise Exception("Value must be larger than 0")

Methods in OOP

In OOP, methods are divided into public methods and private methods. Public methods can be called from other objects, but private methods cannot.

In Python, private methods can be defined with __method_name(self).

class Square:
    def __init__(self, val):
        self.__height = val
        self.__width = val
    def __get_area(self):
        return self.__height**2

square = Square(2)
print(square.__get_area()) # Raises AttributeError

That's all.