self в Python: от основ до продвинутых концепций

Раздел: Продвинутые концепции -> Объектно-ориентированное программирование

В объектно-ориентированном программировании на Python ключевое слово self играет фундаментальную роль. Оно используется для доступа к атрибутам и методам экземпляра класса. Понимание self необходимо для написания корректных и эффективных программ.

Основное понимание self

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

class MyClass:
    def __init__(self, value):
        self.value = value

    def show(self):
        print(self.value)

obj = MyClass(10)
obj.show()  # выведет 10

атрибуты класса python (атрибуты классов и объектов в python)

При вызове obj.show() Python преобразует это в MyClass.show(obj). self указывает на сам объект. Без self метод не сможет обратиться к атрибутам экземпляра.

Как обратиться к атрибутам и методам экземпляра через self?

Через self можно читать и изменять атрибуты, а также вызывать другие методы экземпляра. Например:

class Counter:
    def __init__(self):
        self.count = 0

    def increment(self):
        self.count += 1

    def reset(self):
        self.count = 0

библиотека классов python (библиотека классов в python)

Методы increment и reset работают с атрибутом count через self.

В чем различие между self и cls?

self относится к экземпляру класса, а cls - к самому классу. Методы класса (classmethod) принимают cls в качестве первого параметра. Пример:

class Person:
    species = 'Homo sapiens'

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

    @classmethod
    def get_species(cls):
        return cls.species

print(Person.get_species())  # Homo sapiens

метод объекта python (методы объектов в python)

Здесь self используется в __init__, а cls - в методе класса get_species.

Как создать метод, не требующий доступа к экземпляру?

Статические методы (staticmethod) не имеют self или cls. Они ведут себя как обычные функции, но принадлежат классу.

class MathUtils:
    @staticmethod
    def add(a, b):
        return a + b

print(MathUtils.add(3, 4))  # 7

Python структура объекта (структура объекта в python)

Статические методы полезны для вспомогательных функций, логически связанных с классом.

Как self работает в декораторе property?

self используется в геттерах, сеттерах и удаляторах свойства (property) для доступа к атрибутам экземпляра. Пример:

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, value):
        if value < 0:
            raise ValueError('Radius cannot be negative')
        self._radius = value

Здесь self в геттере и сеттере обращается к защищённому атрибуту _radius.

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

Ошибка: отсутствие self в определении метода
Пример: def method(): pass. При вызове obj.method() Python выдаст TypeError: method() takes 0 positional arguments but 1 was given. Решение: добавить self как первый параметр: def method(self): pass.

Ошибка: обращение к self внутри статического метода
Статический метод не получает self. Если внутри него попытаться использовать self, возникнет NameError (или обращение к глобальному self, если такой определён). Решение: если нужен доступ к экземпляру, используйте обычный метод или метод класса.

Ошибка: неправильное именование self
Можно назвать параметр по-другому, но это нарушает соглашения и ухудшает читаемость. Лучше всегда использовать self.

Ошибка: использование self вместо cls в методе класса
Если метод украшен @classmethod, первый параметр должен называться cls, а не self. Использование self приведёт к путанице, хотя формально код может работать (если не используется внутри). Рекомендуется соблюдать соглашения.

- Object attribute python (атрибуты объекта в python)
- Python call method (вызов метода в python)
- Python класс данных (класс данных в python)

Расширенные примеры использования self

Пример 1: self в __init__ с аргументами по умолчанию

Пример
class Book:
    def __init__(self, title, author='Unknown'):
        self.title = title
        self.author = author
        self._pages = 0

    def add_pages(self, n):
        self._pages += n

b = Book('1984', 'Orwell')
print(b.title, b.author)  # 1984 Orwell
b.add_pages(328)
print(b._pages)            # 328
1984 Orwell
328

Пример 2: self в __call__ для создания вызываемых объектов

Пример
class Multiplier:
    def __init__(self, factor):
        self.factor = factor

    def __call__(self, x):
        return x * self.factor

double = Multiplier(2)
triple = Multiplier(3)
print(double(5))   # 10
print(triple(5))   # 15
10
15

Пример 3: self в __enter__ и __exit__ для контекстного менеджера

Пример
class ManagedFile:
    def __init__(self, filename, mode='r'):
        self.filename = filename
        self.mode = mode
        self.file = None

    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.file:
            self.file.close()

# Использование
with ManagedFile('test.txt', 'w') as f:
    f.write('Hello')
# Файл автоматически закрыт

Пример 4: self с __slots__ для ограничения атрибутов

Пример
class Point:
    __slots__ = ('x', 'y')

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def distance_from_origin(self):
        return (self.x ** 2 + self.y ** 2) ** 0.5

p = Point(3, 4)
print(p.distance_from_origin())  # 5.0
# p.z = 5  # AttributeError: 'Point' object has no attribute 'z'
5.0

Пример 5: self в множественном наследовании с super()

Пример
class A:
    def __init__(self):
        self.a = 1

class B:
    def __init__(self):
        self.b = 2

class C(A, B):
    def __init__(self):
        super().__init__()  # вызовет A.__init__
        self.c = 3

obj = C()
print(obj.a, obj.c)  # 1 3
# Чтобы вызвать B.__init__, нужно явно: B.__init__(self)
1 3

Пример 6: самодельный декоратор свойства через self

Пример
class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius

    def get_fahrenheit(self):
        return self._celsius * 9/5 + 32

    def set_fahrenheit(self, value):
        self._celsius = (value - 32) * 5/9

    # Эмуляция property без декоратора
    fahrenheit = property(get_fahrenheit, set_fahrenheit)

t = Temperature(100)
print(t.fahrenheit)  # 212.0
t.fahrenheit = 32
print(t._celsius)    # 0.0
212.0
0.0

Пример 7: self в методах сравнения (__eq__, __lt__)

Пример
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        if isinstance(other, Person):
            return self.name == other.name and self.age == other.age
        return False

    def __lt__(self, other):
        if isinstance(other, Person):
            return self.age < other.age
        return NotImplemented

alice = Person('Alice', 30)
bob = Person('Bob', 25)
print(alice == bob)  # False
print(alice < bob)   # False (30 не меньше 25)
False
False

Ключевое слово self в классах Python - comments

En
Self x python (python)