Type to search…

Object

An object is a data structure (state) with a set of functions specific to the object that give a different result depending on the state of the object (its attributes).

Introduction

Object-oriented programming was born with Simula in 1962, and its origin is to simulate objects and interactions between objects.

An object is a data structure (state) with a set of functions specific to the object that give a different result depending on the state of the object (its attributes).

Finally, remember that object-oriented programming is invaluable in creating user interfaces, real object simulation programs (such as 3D design), etc., but not in managing processes that process data such as artificial intelligence, web services, etc.

Object

Data structure

Every programming language is composed of simple data structures that allow you to represent anything, for example, a rectangle:

python
rectangle_length = 3
rectangle_width = 6

But if we have two rectangles, how can we represent them?

python
rectangle_a_length = 3
rectangle_a_width = 6

rectangle_b_length = 5
rectangle_b_width = 10

It’s not a good solution. What if we use a list?

python
rectangle_a = [3, 6]
rectangle_b = [5, 10]

In this way, we have the properties of a rectangle grouped in a single data structure under a single reference.

Functions

What if we want to calculate the area of a rectangle?

python
def rectangle_area(length, width):
    return length * width

def test():
    assert rectangle_area(3, 4) == 12

Let’s test if it works.

We create a new project:

ps
uv init test
cd test
uv add --dev pytest

We install the pytest dependency in a development environment since we don’t need it in a production environment (–group dev).

We can now run pytest:

ps
uv run pytest

But didn’t we say we were using a list to represent a rectangle?

python
def rectangle_area(rect):
   return rect[0] * rect[1]

def test():
   rectangle = [3, 6]
   assert rectangle_area(rectangle) == 18

We have a function that calculates the area of a rectangle… only if the list it receives as a parameter represents a rectangle.

The truth is that in somewhat complex code many unforeseen things can happen, because you can say that a list of two values is a rectangle, but for Python it’s just a list.

python
def rectangle_area(rect):
   return rect[0] * rect[1]

def test():

   rectangle = [3, 6]
   assert rectangle_area(rectangle) == 18

   triangle = [3, 6] # base, height
   assert rectangle_area(triangle) == 9

And it might seem obvious because it’s only a few lines, but after a hundred it’s not fun at all.

Classes

That’s why classes exist in Python:

python
class Rectangle:
    def __init__(self, length, width):
        self.length = length
        self.width = width

def rectangle_area(rect):
    return rect.length * rect.width

def test():

    # a cube is not a rectangle
    rectangle = Rectangle(3, 6)
    assert rectangle_area(rectangle) == 18

    triangle = [3, 6] # base, height
    assert rectangle_area(triangle) == 9
shell
$ pytest test.py
rect = [3, 6]
	def rectangle_area(rect):
>   	return rect.length * rect.width
E   	AttributeError: 'list' object has no attribute 'length'

Python uses duck typing. Therefore, the rectangle_area function accepts any object that has two attributes named length and width.

python
class Rectangle:
   def __init__(self, length, width):
       self.length = length
       self.width = width

class Cube:
   def __init__(self, length, width, height):
       self.length = length
       self.width = width
       self.height = height

def rectangle_area(rect):
   return rect.length * rect.width

def test():

   # a cube is not a rectangle
   rectangle = Rectangle(3, 6)
   assert rectangle_area(rectangle) == 18

   cube = Cube(3, 6, 2)
   assert rectangle_area(cube) == 36

Since a cube has the attributes length and width, the rectangle_area function has no problem calculating its area:

When I see a bird that walks like a duck, swims like a duck, and sounds like a duck, I call that bird a duck.

Languages that force you to declare the parameter type do not have this problem.

We can modify the rectangle_area function to verify that the parameter is an instance of the Rectangle class with the isinstance function:

python
class Rectangle:
   def __init__(self, length, width):
       self.length = length
       self.width = width

class Cube:
   def __init__(self, length, width, height):
       self.length = length
       self.width = width
       self.height = height

def rectangle_area(rect):
   assert isinstance(rect, Rectangle)
   return rect.length * rect.width

def test():

   rectangle = Rectangle(3, 6)
   assert rectangle_area(rectangle) == 18

   cube = Cube(3, 6, 2)
   assert rectangle_area(cube) == 36

Now, instead of giving us erroneous data, the function generates a runtime error (in languages like Java the error would be at compile time).

Anyway, if the rectangle_area function should only work with objects of the Rectangle class, why not put it all together?

python
class Rectangle:
   def __init__(self, length, width):
       self.length = length
       self.width = width

   def area(self):
       return self.length * self.width

def test():

   rectangle = Rectangle(3, 6)

   assert rectangle.length == 3
   assert rectangle.area() == 18

By the way, in UML the Rectangle class is represented like this:

To facilitate the creation of diagrams, you can use our guide to use the Mermaid plugin in VSCode.

Exercises

Below is a UML representation of classes, and you must write the corresponding Python code.

Equilateral triangle

Show solution
python
class Triangle:
   def __init__(self, base, height):
       self.base = base
       self.height = height

   def area(self):
       return self.base * self.height

Button

Let’s represent a button in a graphical interface:

And its Python coding would be this:

Show solution
python
class Button:
   def __init__(self, active, message):
       self.active = active
       self.message = message

   def click(self):
       if self.active:
           return self.message
       else:
           return ""

Window

One of the main characteristics of object-oriented programming is object composition.

For example, a window of a graphical interface can have a button:

And its Python coding would be this:

Show solution
python
class Window:
   def __init__(self, title, width, height, content, button):
       self.title = title
       self.width = width
       self.height = height
       self.content = content
       self.button = button

   def resize(self, width, height):
       self.width = width
       self.height = height

We can create an instance of Window and verify its operation:

python
def test():

   window = Window("DAW", 600, 300, "Some content", Button(True, "hello"))
  
   message = window.button.click()
   assert message == "hello"

   window.button.active = False
   message = window.button.click()
   assert message == ""

   window.resize(200, 400)
   assert window.width == 200
   assert window.height == 400

Inheritance

TODO