JavaRush /Курси /Модуль 1: Python Core /Службові методи та поля

Службові методи та поля

Модуль 1: Python Core
Рівень 9 , Лекція 4
Відкрита

5.1 Рівні доступу

Ви, напевно, звернули увагу на дивне ім'я конструктора __init__? В майбутньому ви будете часто зустрічати таке.

У Python існують різні рівні доступу до атрибутів і методів класів, які допомагають контролювати видимість і захищеність даних. Основні механізми управління доступом включають використання одного або двох підкреслень (_ і __) перед іменем атрибута або методу.

Використання угод

Одне підкреслення _ використовується для атрибутів і методів, які не повинні використовуватися поза класом або модулем. Це не заборонено, але це угода, яку слід дотримуватися для кращої читабельності та підтримки коду.

Два підкреслення __ використовуються для атрибутів і методів, які повинні бути дійсно приватними і захищеними від випадкового або навмисного доступу ззовні. Механізм name mangling робить їх менш доступними, але все ще доступними через спеціальні імена.

Публічні (public) поля і методи

Публічні атрибути і методи доступні з будь-якого місця коду. У Python за замовчуванням всі атрибути і методи публічні, якщо їх імена не починаються з підкреслення.


class MyClass:
    def __init__(self):
        self.public_attribute = "I am public"
        
    def public_method(self):
        return "This is a public method"
        

obj = MyClass()
print(obj.public_attribute)  # Доступно
print(obj.public_method())  # Доступно

Через рівні доступу в мові Python реалізується інкапсуляція, а саме через непублічні поля і методи.

5.2 Непублічні поля і методи

Захищені (protected) поля і методи

Захищені атрибути і методи позначаються одним підкресленням _ перед ім'ям і призначені для внутрішнього використання в класі і його підкласах. Це угода, яка каже програмістам про те, що дані не призначені для використання поза класом.


class MyClass:
    def __init__(self):
        self._protected_attribute = "I am protected"
        
    def _protected_method(self):
        return "This is a protected method"
        

obj = MyClass()
print(obj._protected_attribute)  # Доступно, але не рекомендується
print(obj._protected_method())  # Доступно, але не рекомендується

Приватні (private) поля і методи

У Python приватні атрибути і методи позначаються двома підкресленнями __ перед ім'ям. Ці атрибути і методи призначені для використання виключно всередині класу, і їх основна мета — приховати внутрішню реалізацію і захистити дані від випадкової зміни або використання ззовні.

Щоб запобігти прямому доступу до таких атрибутів і методів з зовнішнього коду, Python застосовує спеціальний механізм, відомий як name mangling (спотворення імені). Цей механізм автоматично змінює імена приватних атрибутів, додаючи до них префікс, що складається з імені класу. Таким чином, приватний атрибут __private_attribute у класі MyClass буде перетворений на внутрішнє ім'я _MyClass__private_attribute.

Це дозволяє захистити дані від ненавмисного доступу, зберігаючи при цьому можливість роботи з ними всередині класу. Однак, важливо пам'ятати, що механізм "name mangling" не є абсолютним захистом — досвідчений програміст може отримати доступ до цих даних, використовуючи змінене ім'я.

Давайте розглянемо, як це працює на практиці:


class MyClass:
    def __init__(self):
        self.__private_attribute = "I am private"
        
    def __private_method(self):
        return "This is a private method"
        
    def access_private_method(self):
        return self.__private_method()
         

obj = MyClass()
# print(obj.__private_attribute)  # Помилка, недоступно напряму
# print(obj.__private_method())  # Помилка, недоступно напряму
print(obj.access_private_method())  # Доступно через публічний метод класу

Як видно з прикладу, прямий доступ до приватних атрибутів або методів викликає помилку. Але Python зберігає можливість доступу до них через змінене ім'я. Наприклад, ви можете отримати доступ до приватного атрибута за допомогою "спотвореного" імені, як показано нижче:


class MyClass:
    def __init__(self):
        self.__private_attribute = "I am private"
   
obj = MyClass()
print(obj._MyClass__private_attribute)  # Виведе: I am private

Хоча доступ через "спотворене" ім'я можливий, цього слід уникати, так як це порушує принципи інкапсуляції і може призвести до нестабільності коду.

Щоб побачити, як Python змінює імена атрибутів, ви можете використовувати вбудовану функцію dir(), яка відображає всі доступні атрибути і методи об'єкта:


class MyClass:
    def __init__(self):
        self.__private_attribute = "I am private"
   
obj = MyClass()
print(dir(obj))  # Виводить всі атрибути і методи об'єкта, включаючи "спотворені" імена

В результаті виконання функції dir() ви побачите список всіх атрибутів і методів об'єкта, включаючи _MyClass__private_attribute, що підтверджує механізм "name mangling".

5.3 Автоматичний виклик методів

Був один цікавий аспект при роботі з конструкторами, на який ви, можливо, звернули увагу. Метод __init__ викликався автоматично.

Насправді таких ситуацій досить багато, як і методів на ці випадки. Приклади:

Метод __str__

Якщо у вашого об'єкта є метод __str__, то він буде викликаний автоматично при спробі перетворити ваш об'єкт у рядок, наприклад, при використанні функцій print() і str().


class Cat:
    def __init__(self, name, age):
        self.name = name
        self.age = age
            
    def __str__(self):
        return f"{self.name} is {self.age} years old"
            

cat = Cat("Barsik", 5)
print(cat)  # Виведе: Barsik is 5 years old

Метод __len__

А якщо у вашого об'єкта є метод __len__, то він буде викликаний автоматично при спробі визначити «довжину» вашого об'єкта — використовується функцією len(). Приклад:


class MyList:
    def __init__(self, items):
        self.items = items
        
    def __len__(self):
        return len(self.items)
        
        
my_list = MyList([1, 2, 3])
print(len(my_list))  # Виведе: 3

Таких «службових методів» ще буде багато у вашому житті, але працювати з ними одне задоволення. Тож готуйтеся :)

Коментарі (3)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
Semen Рівень 21
4 липня 2025
Щось я не зрозумів, для чого атрибут назвали"_model_"? Щоб визначити його як protected, його можна було назвати "_model", хіба ні?
Dmytro Рівень 29
20 грудня 2025
Це не критично
Дмитро Рівень 30
24 січня 2026
так, вірно _model