Object-Oriented Python

Build classes and objects to model security tools — encapsulate scanner logic, extend base classes, and use dunder methods.

Medium 60m 3 tasks
Prerequisites: File I/O & JSON

Learning Objectives

  • Define classes with __init__ and instance methods
  • Use encapsulation to hide internal state
  • Implement inheritance and method overriding
  • Use dunder methods (__str__, __repr__, __len__)
  • Model a real security tool using OOP principles

Classes and Objects

class Scanner:
    def __init__(self, host, timeout=1.0):
        self.host    = host
        self.timeout = timeout
        self._results = {}     # 'private' by convention

    def scan_port(self, port):
        import socket
        try:
            with socket.create_connection((self.host, port), self.timeout):
                self._results[port] = "open"
        except OSError:
            self._results[port] = "closed"

    def get_open_ports(self):
        return [p for p, s in self._results.items() if s == "open"]

    def __str__(self):
        return f"Scanner({self.host}) — {len(self._results)} ports checked"

    def __len__(self):
        return len(self._results)

s = Scanner("127.0.0.1")
s.scan_port(22)
s.scan_port(80)
print(s)                  # Scanner(127.0.0.1) — 2 ports checked
print(s.get_open_ports())

Class vs Instance Variables

class Target:
    count = 0    # class variable — shared by all instances

    def __init__(self, ip):
        Target.count += 1
        self.ip = ip          # instance variable
        self.id = Target.count

t1 = Target("10.0.0.1")
t2 = Target("10.0.0.2")
print(Target.count)   # 2
print(t1.id, t2.id)   # 1 2

Inheritance

class BaseExploit:
    def __init__(self, target):
        self.target = target

    def connect(self):
        raise NotImplementedError

    def run(self):
        self.connect()
        self.execute()

class SSHBruteforce(BaseExploit):
    def __init__(self, target, wordlist):
        super().__init__(target)
        self.wordlist = wordlist

    def connect(self):
        print(f"Connecting to {self.target} via SSH")

    def execute(self):
        for word in self.wordlist:
            print(f"  Trying: {word}")

class FTPBruteforce(BaseExploit):
    def connect(self):
        print(f"Connecting to {self.target} via FTP")

    def execute(self):
        print("Running FTP attack")

Properties (Getters/Setters)

class Target:
    def __init__(self, ip):
        self._ip = ip

    @property
    def ip(self):
        return self._ip

    @ip.setter
    def ip(self, value):
        parts = value.split(".")
        if len(parts) != 4:
            raise ValueError(f"Invalid IP: {value}")
        self._ip = value

t = Target("192.168.1.1")
print(t.ip)       # getter
t.ip = "10.0.0.1"  # setter with validation

Dunder Methods

Method Purpose
__init__ Constructor
__str__ Human-readable string (print)
__repr__ Developer representation
__len__ len(obj) support
__eq__ Equality comparison
__lt__ Less-than (enables sorting)
__iter__ Makes object iterable

Mini Project – ScanReport Class

class ScanReport:
    def __init__(self, host):
        self.host  = host
        self._data = {}

    def add_result(self, port, status, service=""):
        self._data[port] = {"status": status, "service": service}

    def open_ports(self):
        return [p for p, d in self._data.items() if d["status"] == "open"]

    def to_dict(self):
        return {"host": self.host, "results": self._data}

    def __repr__(self):
        return f"ScanReport(host={self.host!r}, ports={len(self._data)})"

    def __len__(self):
        return len(self.open_ports())

r = ScanReport("192.168.1.1")
r.add_result(22,  "open",   "SSH")
r.add_result(80,  "open",   "HTTP")
r.add_result(443, "closed", "HTTPS")
print(r)
print(f"Open ports: {r.open_ports()}")

Implement the Scanner class from the lesson. Add a scan_range(start, end) method that calls scan_port for each port in the range. Test it against localhost.

✦ Answer the questions to complete this task

What method is called when an object is created?

What keyword accesses the current instance inside a method?

Create a BaseTool class with __init__(self, target) and a run() method that calls execute(). Then create NmapTool and DirbTool subclasses that override execute(). Show polymorphism by calling .run() on both.

✦ Answer the questions to complete this task

What function calls the parent class's __init__?

Implement ScanReport. Add a to_json() method that returns json.dumps(self.to_dict()). Add __eq__ that compares hosts. Create two reports for the same host and verify equality.

✦ Answer the questions to complete this task

Which dunder method enables == comparison between objects?

💪 Exercises & Challenges

📝 MCQ Medium +20 XP

OOP in Python MCQ

MCQ: OOP in Python MCQ

Start →
⚙️ Practical Medium +30 XP

Port Scanner OOP Refactor

Port Scanner OOP Refactor

Start →
🚩 Challenge Hard +50 XP

OOP Flag Hunt

OOP Flag Hunt

Start →