Клас – є своєрідним планом (кресленням), на основі котрого створюються конкретні екземпляри (об’єкти) цього класу. Клас описує визначену структуру (тип), котра містить власні дані та функції, доступ до яких можна отримати створивши екземпляр цього класу.

  • класи є важливим інструментом для групування даних та функціональних можливостей
  • оголошення нового класу створює новий тип об’єктів, що в свою чергу дозволяє створювати екземпляри цього типу
  • кожен екземпляр класу може мати атрибути, на основі котрих формується його стан
  • екземпляри класу також можуть мати методи (визначені їхнім класом), котрі формують його поведінку та можуть змінювати його стан

Приклад оголошення класу в Python

Класи створюються за допомогою ключового слова class:

class BankAccount:
    pass

Поки що клас BankAccount не містить в собі чогось корисного. Інструкція pass виступає своєрідною заглушкою, яка дозволяє програмі пропустити цей розділ коду, не роблячи нічого.

Створення екземпляра класу в Python

Код котрий створює новий екземпляр класу BankAccount, та призначає посилання на цей об’єкт змінній obj:

obj = BankAccount()

print(type(obj))
print(isinstance(obj, BankAccount))

# <class '__main__.BankAccount'>
# True

Вбудована у Python функція type, повертає тип об’єкта. Функція isinstance повертає True, якщо об’єкт (перший аргумент), є екземпляром вказаного типу (другий аргумент), в іншому випадку функція поверне False.

Ми можемо мати скільки завгодно об’єктів класу, в кожного з котрих буде своя ідентифікація та стан, незалежні від інших екземплярів (для прикладу з BankAccount, це можуть бути номер рахунку та його баланс).

Змінні класу та екземпляра

  • змінні класу призначені для атрибутів, значення котрих є спільними для всіх його екземплярів
  • змінні екземпляра призначені для даних, котрі відносяться до конкретного екземпляра класу, та не залежать від інших екземплярів

Додамо змінні класу та екземпляра в оголошення BankAccount:

class BankAccount:
    prefix = 'UA'
    
    def __init__(self, account_number, balance):
        self.account_number = account_number
        self.balance = balance

В цьому прикладі prefix є змінною класу, account_number та balance є змінними екземпляра.

Слід звернути увагу, що значення змінної класу присвоюється на рівні класу, а значення змінних екземпляра всередині конструктора (метод init), або методів котрі першим аргументом приймають посилання на поточний екземпляр класу (зазвичай цей аргумент має ім’я self).

Метод __init__

Метод __init__ в Python, подібний до конструктора в Java. Конструктор використовується для ініціалізації стану об’єкта, та містить набір інструкцій, котрі виконуються під час створення об’єкта:

def __init__(self, account_number, balance):
    self.account_number = account_number
    self.balance = balance

В цьому прикладі, метод __init__ буде запускатись одразу, при створенні об’єкта класу BankAccount, та будуть виконані інструкції з ініціалізації змінних екземпляра (account_number, balance).

Аргумент self

Для прикладу додаю до класу BankAccount метод, котрий поповнює баланс:

def deposit(self, amount):
    self.balance += amount

Тепер створюю об’єкт класу та викликаю метод deposit:

obj = BankAccount("55", 1000)

obj.deposit(1000)
print(obj.balance)

# 2000

Коли відбувається виклик методу об’єкта, у вигляді obj.method(arg), Python автоматично перетворює його в Class.method(object, arg). Аргумент self є посиланням на конкретний об’єкт класу, що дає змогу отримати в тілі метода доступ до поточного стану екземпляра і змінювати його (в прикладі вище оновлення balance).

Ім’я self є домовленістю, якщо назвати цей аргумент інакше, код буде працювати так само (хоча робити цього не бажано).

Статичні методи, методи класу та екземпляра класу

Python пропонує три види методів: статичні, класу та екземпляра класу. Про статичні методи та методи класу можна прочитати в окремому дописі: Декоратори @staticmethod та @classmethod в Python

Методи екземпляра класу – приймають поточний об’єкт класу першим аргументом (котрий прийнято називати self і який вказує на сам екземпляр).

Методи екземплярів класу дозволяють змінювати стан поточного об’єкта класу:

def deposit(self, amount):
    self.balance += amount

В цьому прикладі, метод екземпляра deposit(self, amount), змінює його стан (а саме поповнює баланс). Ці зміни будуть стосуватись лише того об’єкта, на котрому було зроблено виклик метода:

obj_1 = BankAccount("1", 1000)
obj_2 = BankAccount("2", 1000)

obj_1.deposit(1000)

print(obj_1.balance)
print(obj_2.balance)

# 2000
# 1000

Метод __str__

Після створення екземпляра класу, він має рядкове представлення за замовчуванням, яке можна побачити при використанні функції print:

obj = BankAccount("1", 1000)

print(obj)

# <__main__.BankAccount object at 0x00000149ED967FD0>

Виглядає не зовсім інформативно для звичайного користувача.

Python має спеціальний метод __str__, котрий використовується для визначення способу представлення об’єкта класу у вигляді рядка. Він часто використовується для того, щоб надати об’єкту читабельне для людини текстове представлення, яке є корисним для ведення логування, налагодження або показу користувачам інформації про об’єкт.

Додаю в клас BankAccount власну реалізацію метода __str__ (рядок 11):

class BankAccount:
    prefix = 'UA'

    def __init__(self, account_number, balance):
        self.account_number = account_number
        self.balance = balance

    def deposit(self, amount):
        self.balance += amount

    def __str__(self):
        return f'Bank Account: {self.prefix}{self.account_number}, ' \
               f'balance: {self.balance}'


obj = BankAccount("1", 1000)

print(obj)

# Bank Account: UA1, balance: 1000

Об’єкти класу

  • Після оголошення класу, ми можемо створювати скільки завгодно його об’єктів.
  • Кожен об’єкт може мати свій стан, незалежний від інших об’єктів (сукупність значень змінних екземпляра).
  • Всі об’єкти можуть мати загальну поведінку, визначену в класі (методи екземпляра, котрі приймають в якості першого аргументу посилання на екземпляр – self).
class BankAccount:
    prefix = 'UA'

    def __init__(self, account_number, balance):
        self.account_number = account_number
        self.balance = balance

    def deposit(self, amount):
        self.balance += amount

    def __str__(self):
        return f'Bank Account: {self.prefix}{self.account_number}, ' \
               f'balance: {self.balance}'


obj_1 = BankAccount("1", 1000)
obj_2 = BankAccount("2", 500)

obj_1.deposit(2000)

print(obj_1)
print(obj_2)

# Bank Account: UA1, balance: 3000
# Bank Account: UA2, balance: 500

В цьому прикладі створено два об’єкти класу BankAccount (рядок 16-17), після чого в одному з них змінено стан балансу (рядок 19). Вивід строкового представлення об’єктів (рядок 21-22), демонструє незалежність їх станів.


Мітки: