У Python self є невід’ємною частиною об’єктно-орієнтованого програмування. Це слово використовується всередині методів класу для звернення до атрибутів та методів поточного екземпляра.

Що означає self

У методах класу завжди присутній спеціальний перший параметр – self. Він автоматично містить посилання на екземпляр об’єкта, з яким викликається метод.

self дає можливість:

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

Чи є self зарезервованим словом?

Ні, self не є зарезервованим словом у Python. Це лише усталена угода про іменування першого параметра методу класу. Теоретично ви можете використати будь-яке інше ім’я (наприклад, this), і код працюватиме. Однак у Python-спільноті завжди використовують саме self, і відхилення від цієї домовленості вважається поганою практикою, оскільки робить код менш зрозумілим для інших розробників.

Чому self завжди перший параметр

Коли ми викликаємо метод об’єкта, наприклад:

user.greet()

Python «під капотом»  перетворює його на виклик:

User.greet(user)

Тобто сам об’єкт автоматично передається у метод першим аргументом і стає значенням параметра self. Саме тому у сигнатурі методів він завжди стоїть першим.

Приклад використання

class User:
    def __init__(self, username, age):  # конструктор класу
        self.username = username
        self.age = age

    def greet(self):
        return f'Hello, my name is {self.username} and I am {self.age} years old.'


user = User('Alex', 25)
print(user.greet())

# Hello, my name is Alex and I am 25 years old.

Пояснення:

  • Метод __init__ – це конструктор класу, який викликається автоматично під час створення нового об’єкта User('Alex', 25).
  • Перший параметр self у конструкторі (так само як і в інших методах), посилається на новостворений екземпляр.
  • Завдяки цьому під час ініціалізації можна зберігати дані у атрибутах конкретного об’єкта (self.username, self.age).
  • Коли викликається user.greet(), Python трансформує його у виклик User.greet(user). Об’єкт user автоматично підставляється як self, і ми отримуємо доступ до атрибутів, визначених у конструкторі.

Для чого потрібен self

1. Доступ до властивостей об’єкта:

class Car:
    def __init__(self, brand):
        self.brand = brand

    def show_brand(self):
        return f'This car is a {self.brand}.'

2. Виклик інших методів того ж об’єкта:

class User:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    def get_full_name(self):
        return f'{self.first_name} {self.last_name}'

    def greet(self):
        full_name = self.get_full_name()
        return f'Hello, {full_name}!'

3. Відокремлення рівня класу і рівня екземпляра:

self завжди вказує на конкретний екземпляр. Але в Python є методи, що працюють без нього:

  • @staticmethod – не отримує self, бо працює як звичайна функція, «прив’язана» до класу
  • @classmethod – замість self отримує параметр cls, який посилається на сам клас
class Example:
    def instance_method(self):
        return f'instance method, self = {self}'

    @staticmethod
    def static_method():
        return 'static method (no self, no cls)'

    @classmethod
    def class_method(cls):
        return f'class method, cls = {cls}'


ex = Example()
print(ex.instance_method())
print(Example.static_method())
print(Example.class_method())

#  instance method, self = <__main__.Example object at 0x000001B516C87E20>
#  static method (no self, no cls)
#  class method, cls = <class '__main__.Example'>

Докладніше про декоратори @staticmethod та @classmethod в Python.

Можливі помилки

1. Забути додати self у сигнатуру методу:

class Test:
    def say_hello():  # помилка
        print('Hello')


test = Test()
test.say_hello()

# TypeError: Test.say_hello() takes 0 positional arguments but 1 was given

Виклик test.say_hello() призведе до помилки TypeError, оскільки Python автоматично передає екземпляр test у метод як перший аргумент, у той час коли сигнатура методу його не очікує.

2. Плутати змінні класу і змінні екземпляра:

class Dog:
    species = 'Canine'  # змінна класу (спільна для всіх екземплярів)

    def __init__(self, name):
        self.name = name  # змінна екземпляра (унікальна для кожного об’єкта)


dog1 = Dog('Rex')
dog2 = Dog('Buddy')

print(dog1.name)  # Rex
print(dog2.name)  # Buddy

print(dog1.species)  # Canine
print(dog2.species)  # Canine

Пояснення:

  • species – змінна класу. Вона спільна для всіх Dog. Якщо змінити її на рівні класу Dog.species = 'Wolf', то зміна відобразиться у всіх екземплярах.
  • name – змінна екземпляра. Кожен об’єкт зберігає своє власне ім’я, незалежно від інших.

Таким чином, self потрібен саме для доступу до індивідуальних даних кожного об’єкта, тоді як змінні класу існують незалежно від конкретних екземплярів.

Порівняння з іншими мовами програмування

У мовах Java та C# посилання на поточний екземпляр this передається неявно. У цих мовах this є ключовим словом, яке компілятор автоматично робить доступним всередині нестатичних методів класу. Вам не потрібно оголошувати його як параметр методу.

Приклад на Java:

class User {
    private String name;

    User(String name) {
        this.name = name; // this доступне автоматично
    }

    void greet() {
        System.out.println("Hello, my name is " + this.name);
    }
}

У Python все інакше: посилання на екземпляр передається явно – через параметр self:

class User:
    def __init__(self, name):
        self.name = name  # self передається явно

    def greet(self):
        print(f'Hello, my name is {self.name}')

Завдяки цьому Python-код стає більш прозорим: у сигнатурі методу ми одразу бачимо, що він належить екземпляру, і доступ до атрибутів/методів здійснюється саме через self.

Підсумок

self – це спосіб, за допомогою якого Python передає поточний екземпляр класу у метод. Він дає можливість:

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

Без self методи б не знали, з яким саме об’єктом вони повинні працювати.


Мітки: