tariel.ge › Полезное: бесплатные книги › Программирование: от нулей и единиц до PythonБесплатно · автор Тариел Бежанидзе
← Учебник по программированию ЛИСТ 24БЛОК 5 — ЧТО ДОБАВИЛИ ОТ СЕБЯРЕВ. 1
Глава 24 · Что добавили от себя

Основы ООП: классы и объекты

В главе 08 мельком упоминалось, что C++ принёс в индустрию смену парадигмы — объекты вместо чистых процедур. Здесь наконец видно, что это значит на практике, и почему это не просто другой синтаксис для того же самого.

От раздельных данных и функций — к объединению

Весь код этой книги до сих пор был написан в процедурном стиле: данные (переменные, списки, словари) и функции, которые их обрабатывают, существуют отдельно друг от друга — функция принимает данные как аргумент и что-то с ними делает. Объектно-ориентированный подход предлагает другую модель: объединить данные и работающие с ними функции (называемые в этом контексте методами) в единую сущность — объект.

Класс — чертёж, объект — конкретная вещь по этому чертежу

class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def bark(self):
        print(f"{self.name} говорит: Гав!")

my_dog = Dog("Рекс", 3)
my_dog.bark() # Рекс говорит: Гав!

class Dog: описывает шаблон — какие данные (атрибуты) и какое поведение (методы) есть у любой собаки в терминах этой программы. my_dog — конкретный объект (экземпляр), созданный по этому шаблону, с собственными конкретными значениями атрибутов.

__init__ и self — что это и зачем

__init__ — специальный метод, автоматически вызываемый в момент создания нового объекта — конструктор, задающий начальное состояние объекта. self — первый параметр каждого метода класса, ссылающийся на тот конкретный объект, с которым сейчас работает код — именно через self.name метод получает доступ к данным именно этого экземпляра, а не какого-то другого объекта того же класса.

Практический смысл self

Если создать двух разных собак (Dog("Рекс", 3) и Dog("Бобик", 5)), у каждой будет собственное значение self.name и self.age — несмотря на то, что метод bark() определён в классе всего один раз, вызов my_dog.bark() и other_dog.bark() обратится к данным именно того объекта, у которого метод был вызван — self и есть тот самый механизм, который это обеспечивает.

Практический пример: превращаем функции главы 23 в класс

class LogAnalyzer:
    def __init__(self, log_path):
        self.log_path = log_path
        self.counts = {}

    def analyze(self):
        with open(self.log_path, encoding="utf-8") as f:
            for line in f:
                parts = line.strip().split(" ")
                if len(parts) >= 2:
                    level = parts[1]
                    self.counts[level] = self.counts.get(level, 0) + 1

    def most_common(self):
        return max(self.counts, key=self.counts.get)

analyzer = LogAnalyzer("app.log")
analyzer.analyze()
print(analyzer.most_common())

Разница с функциональной версией из главы 23: self.log_path и self.counts "живут" вместе с объектом между вызовами методов — не нужно передавать их как аргументы в каждую функцию заново, объект сам "помнит" своё состояние. Это особенно удобно, когда данных и связанных с ними операций становится много.

Наследование — переиспользование и расширение

class Animal:
    def __init__(self, name):
        self.name = name

    def describe(self):
        print(f"Это {self.name}")

class Dog(Animal): # Dog наследует всё от Animal
    def bark(self):
        print(f"{self.name} говорит: Гав!")

rex = Dog("Рекс")
rex.describe() # унаследовано от Animal — Это Рекс
rex.bark() # собственный метод Dog — Рекс говорит: Гав!

Класс Dog(Animal) автоматически получает всё, что определено в Animal, и может добавлять собственные методы или переопределять унаследованные. Это позволяет выстраивать иерархии связанных классов, не копируя общий код в каждый из них заново — прямое продолжение принципа DRY, уже прозвучавшего в главе 16.

Зачем это вообще нужно на практике

Большая часть популярных библиотек Python (включая многое из следующих глав — работа с последовательным портом в главе 26) устроена именно в объектном стиле: подключение к устройству возвращает объект, у которого есть методы для чтения, записи, закрытия соединения — состояние (открыто ли соединение, какой порт) естественно живёт вместе с этим объектом, а не передаётся отдельным набором переменных в каждую функцию.

Что дальше

Следующая глава — тема, без которой ни один код, включая написанный в этой главе, не может считаться профессионально завершённым: Git, система версионирования, отслеживающая историю изменений кода.

Глава24 — Основы ООП
Блок5 — Что добавили от себя
Далее25 — Git
СтатусГотово · рев. 1
Предыдущая глава ← 23 · Скрипты автоматизации Следующая глава 25 · Git →

Книга бесплатна для чтения. Автор — Тариел Бежанидзе, компьютерный мастер в Батуми · tariel.ge · все бесплатные книги. Копировать текст целиком на другие сайты — только со ссылкой на источник.