8-916-722-04-28ТелВКонтактеВКTelegramTgMAXMAX Пробный урокПробный урок

Класс, объект, атрибуты, методы, инкапсуляция на примере простого класса на Python

От процедурного программирования к объектному

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

Класс и объект

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

class Dog:

pass # пока пустой класс — просто демонстрация синтаксиса

# Создание объектов (экземпляров) класса Dog

rex = Dog()

bobik = Dog()

print(type(rex)) # <class '__main__.Dog'>

print(rex is bobik) # False — это два разных объекта

Атрибуты объекта и конструктор __init__

Атрибуты — это переменные, хранящие данные (характеристики) конкретного объекта. Чтобы задать атрибуты при создании объекта, в классе определяют специальный метод __init__ — конструктор, который автоматически вызывается при создании нового объекта и получает значения для его атрибутов. Первый параметр любого метода класса, включая __init__, называется self и представляет собой ссылку на тот объект, для которого метод вызывается; через self внутри методов обращаются к атрибутам именно этого объекта.

class Student:

def __init__(self, name, grade):

self.name = name # атрибут — имя ученика

self.grade = grade # атрибут — класс обучения

self.scores = [] # атрибут — список оценок

# Создание объектов с разными значениями атрибутов

student1 = Student('Анна', 11)

student2 = Student('Пётр', 10)

print(student1.name, student1.grade) # Анна 11

print(student2.name, student2.grade) # Пётр 10

Методы класса

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

class Student:

def __init__(self, name, grade):

self.name = name

self.grade = grade

self.scores = []

def add_score(self, score):

self.scores.append(score)

def average_score(self):

if not self.scores:

return 0

return sum(self.scores) / len(self.scores)

student1 = Student('Анна', 11)

student1.add_score(5)

student1.add_score(4)

student1.add_score(5)

print(student1.scores) # [5, 4, 5]

print(student1.average_score()) # 4.666…

Создание нескольких объектов одного класса

Главное преимущество класса — возможность создавать сколько угодно независимых объектов на его основе; изменение атрибутов одного объекта никак не влияет на атрибуты другого, даже если оба созданы из одного и того же класса.

students = [Student('Анна', 11), Student('Пётр', 11), Student('Мария', 11)]

students[0].add_score(5)

students[0].add_score(5)

students[1].add_score(3)

students[1].add_score(4)

students[2].add_score(5)

students[2].add_score(4)

for s in students:

print(f'{s.name}: средний балл {s.average_score():.2f}')

Инкапсуляция данных

Инкапсуляция — один из ключевых принципов ООП, заключающийся в объединении данных и методов их обработки внутри объекта и в ограничении прямого доступа извне к внутренним данным объекта, если это нежелательно. В Python нет строгого запрета доступа к атрибутам, как в некоторых других языках, но принято обозначать «внутренние», не предназначенные для прямого использования извне атрибуты одним подчёркиванием в начале имени (_balance) — как соглашение для программистов, а двумя подчёркиваниями (__balance) — для более сильной защиты (имя такого атрибута автоматически изменяется интерпретатором, что затрудняет случайное обращение к нему извне). Вместо прямого доступа к таким атрибутам создают специальные методы, которые контролируют, каким образом атрибут можно читать или изменять.

class BankAccount:

def __init__(self, owner, balance=0):

self.owner = owner

self.__balance = balance # 'приватный' атрибут

def deposit(self, amount):

if amount > 0:

self.__balance += amount

def withdraw(self, amount):

if 0 < amount <= self.__balance:

self.__balance -= amount

else:

print('Недостаточно средств или неверная сумма')

def get_balance(self):

return self.__balance

account = BankAccount('Иван', 1000)

account.deposit(500)

account.withdraw(2000) # 'Недостаточно средств или неверная сумма'

print(account.get_balance()) # 1500

Метод __str__ для удобного вывода объекта

По умолчанию при попытке напечатать объект (print(obj)) Python выводит малоинформативную строку вида <__main__.Student object at 0x…>. Чтобы задать понятное текстовое представление объекта, в классе определяют специальный метод __str__, который автоматически вызывается функцией print() и должен возвращать строку.

class Student:

def __init__(self, name, grade):

self.name = name

self.grade = grade

def __str__(self):

return f'Ученик {self.name}, {self.grade} класс'

student1 = Student('Анна', 11)

print(student1) # Ученик Анна, 11 класс

Атрибуты класса и атрибуты объекта

Помимо атрибутов конкретного объекта, задаваемых через self в конструкторе, в классе можно объявить атрибут класса — переменную, объявленную непосредственно внутри тела класса, но вне какого-либо метода. Такой атрибут является общим для всех объектов класса: если не переопределить его индивидуально для конкретного объекта, все объекты будут видеть одно и то же значение. Атрибуты класса удобны для хранения общих для всех объектов данных, например счётчика количества уже созданных объектов.

class Student:

school_name = 'Школа №1' # атрибут класса — общий для всех

total_students = 0 # счётчик созданных объектов

def __init__(self, name):

self.name = name # атрибут объекта — свой у каждого

Student.total_students += 1

s1 = Student('Анна')

s2 = Student('Пётр')

print(s1.school_name, s2.school_name) # оба видят одно и то же значение

print('Всего учеников создано:', Student.total_students) # 2

Полный пример: класс Rectangle

Рассмотрим итоговый пример класса «Прямоугольник», объединяющего атрибуты (ширину и высоту), методы для вычисления производных величин (площади и периметра), инкапсуляцию (проверку корректности значений при создании) и удобное текстовое представление.

class Rectangle:

def __init__(self, width, height):

if width <= 0 or height <= 0:

raise ValueError('Стороны должны быть положительными')

self.width = width

self.height = height

def area(self):

return self.width * self.height

def perimeter(self):

return 2 * (self.width + self.height)

def is_square(self):

return self.width == self.height

def __str__(self):

return f'Прямоугольник {self.width}x{self.height}'

rectangles = [Rectangle(4, 5), Rectangle(3, 3), Rectangle(7, 2)]

for r in rectangles:

print(f'{r}: площадь={r.area()}, периметр={r.perimeter()}, квадрат={r.is_square()}')

ООП и уже изученные структуры данных

Атрибутом объекта может быть не только число или строка, но и любая другая изученная структура данных — список, строка или даже другой объект. Это позволяет классу естественно объединять коллекцию данных с методами её обработки: например, класс «Группа» может хранить список объектов класса Student и предоставлять методы для вычисления среднего балла всей группы, используя ровно те же приёмы обхода массива и суммирования, которые уже были рассмотрены при изучении одномерных массивов.

class Group:

def __init__(self, students):

self.students = students # список объектов класса Student

def group_average(self):

total = 0

count = 0

for s in self.students:

total += s.average_score()

count += 1

return total / count if count else 0

group = Group([Student('Анна', 11), Student('Пётр', 11)])

group.students[0].add_score(5)

group.students[1].add_score(4)

print(f'Средний балл группы: {group.group_average():.2f}')

Типичные ошибки

Самая частая ошибка начинающих — забыть указать параметр self первым параметром метода, что приводит к ошибке TypeError при вызове метода (Python автоматически передаёт объект первым аргументом). Вторая ошибка — путать атрибут класса (общий для всех объектов, объявленный внутри класса, но вне __init__) с атрибутом объекта (индивидуальным, задаваемым через self в __init__): изменение изменяемого атрибута класса (например, списка) через один объект неожиданно затрагивает все объекты этого класса. Третья ошибка — обращение к атрибуту объекта до его создания в __init__ (например, использование self.total до строки self.total = 0), что вызывает AttributeError. Наконец, часто забывают, что вызов метода объекта происходит через точку: obj.method(), а не method(obj) или Class.method() без указания объекта.

Краткий словарь терминов

Класс — шаблон (описание), определяющий атрибуты и методы будущих объектов.

Объект (экземпляр класса) — конкретная реализация класса с собственными значениями атрибутов.

Атрибут — переменная, хранящая данные (характеристику) объекта.

Метод — функция, определённая внутри класса и описывающая поведение объекта.

self — первый параметр метода, ссылающийся на тот объект, для которого метод вызван.

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

Инкапсуляция — объединение данных и методов внутри объекта с ограничением прямого доступа к внутренним данным извне.

Заключение

Классы и объекты позволяют объединять данные и обрабатывающие их алгоритмы в единые, самостоятельные и легко переиспользуемые сущности, что делает объектно-ориентированный подход основой для построения больших и хорошо структурированных программ. Освоенные в этом разделе структуры данных, алгоритмы и принципы ООП образуют фундамент программирования, необходимый как для решения задач ЕГЭ по информатике, так и для дальнейшего изучения профессиональной разработки программного обеспечения.

Запишитесь на бесплатный урок

Определим уровень, покажем формат занятий и составим план подготовки.