self в Python: от основ до нюансов объектно-ориентированного программирования
Основная концепция self
Параметр self является обязательным первым параметром любого метода экземпляра класса. Он представляет собой ссылку на конкретный объект (экземпляр), для которого вызывается метод. При вызове метода через объект Python автоматически передает сам объект в качестве первого аргумента.
class MyClass:
def method(self, arg):
print(f"Метод вызван для {self}, аргумент {arg}")
obj = MyClass()
obj.method(10)
атрибуты класса python (атрибуты классов и объектов в python)
Метод вызван для <__main__.MyClass object at 0x...>, аргумент 10
библиотека классов python (библиотека классов в python)
Без использования self невозможно обратиться к атрибутам и другим методам данного экземпляра внутри класса.
Можно ли использовать другое имя вместо self?
Да, self не является ключевым словом, а лишь общепринятым соглашением. Можно назвать параметр любым именем, например this или myself. Однако отступление от стандарта ухудшает читаемость кода.
class Example:
def __init__(this, value):
this.value = value
def show(myself):
print(myself.value)
метод объекта python (методы объектов в python)
Такой код будет работать, но не рекомендуется.
Проблема: при переименовании self сложнее понимать код другим разработчикам. IDE могут не подсвечивать правильно.
Как обойтись без self в методе? (статические методы)
Если метод не нуждается в доступе к экземпляру, его объявляют статическим с помощью декоратора @staticmethod. В этом случае параметр self не передаётся.
class Calculator:
@staticmethod
def add(a, b):
return a + b
print(Calculator.add(5, 3))
метод call python (метод __call__ в python)
8
Python структура объекта (структура объекта в python)
Статические методы используются для вспомогательных функций, логически принадлежащих классу.
Зачем нужен cls вместо self? (классовые методы)
Для методов, работающих с классом в целом, применяется декоратор @classmethod. Первым параметром передаётся класс (cls), а не экземпляр.
class MyClass:
count = 0
def __init__(self):
MyClass.count += 1
@classmethod
def get_count(cls):
return cls.count
Python создание объектов (создание объектов в python)
a = MyClass()
b = MyClass()
print(MyClass.get_count())
Self object python (объект self в python)
2
Object attribute python (атрибуты объекта в python)
Классовые методы часто используются для фабричных методов.
Как self используется в конструкторе? (магические методы)
Параметр self обязателен и в методе __init__. Через него устанавливаются начальные атрибуты экземпляра.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name}, {self.age} лет"
Python call method (вызов метода в python)
p = Person("Алиса", 30)
print(p)
Python класс данных (класс данных в python)
Алиса, 30 лет
Class method python (методы классов в python)
Помимо __init__, self используется в __repr__, __eq__ и других магических методах.
Как возвращать self для цепочки вызовов?
Методы могут возвращать self, чтобы обеспечить последовательный вызов нескольких методов на одном объекте (fluent interface).
class Builder:
def __init__(self):
self.parts = []
def add_part(self, part):
self.parts.append(part)
return self
def build(self):
print("Собрано:", ", ".join(self.parts))
b = Builder()
b.add_part("Колесо").add_part("Двигатель").build()
Python object methods (методы объектов в python)
Собрано: Колесо, Двигатель
класс python определение (определение классов в python)
Каждый метод возвращает self, позволяя вызывать следующий метод через точку.
Типичные ошибки и их решение
Забыли self в определении метода:
class Bad:
def method(arg): # нет self
print(arg)
При вызове obj.method(10) возникает ошибка TypeError: method() takes 1 positional argument but 2 were given, потому что экземпляр передаётся как первый аргумент, а метод ожидает один. Решение: добавить self.
Передача self явно: Иногда новички пишут obj.method(obj, arg), что приводит к двойной передаче экземпляра. Достаточно вызвать метод с одним аргументом, self передаётся автоматически.
Путаница между self и cls: В классовых методах первый параметр - cls, а не self. Если ошибочно написать self, то при обращении к self внутри классового метода будет ошибка атрибута.
Расширенные примеры использования self
Пример 1: Явный вызов метода родителя через self
class Parent:
def show(self):
print("Parent.show")
class Child(Parent):
def show(self):
Parent.show(self) # явная передача self
print("Child.show")
c = Child()
c.show()
Parent.show Child.show
В этом примере метод дочернего класса вызывает метод родителя, передавая self вручную. Альтернативой служит super().show(), но явная передача self иногда применяется при множественном наследовании.
Пример 2: self в контекстном менеджере (__enter__ / __exit__)
class FileManager:
def __init__(self, filename):
self.filename = filename
def __enter__(self):
self.file = open(self.filename, 'w')
return self.file
def __exit__(self, exc_type, exc_value, traceback):
self.file.close()
with FileManager('test.txt') as f:
f.write('Hello')
Здесь self хранит имя файла и сам файловый объект. Метод __enter__ возвращает объект файла, а __exit__ закрывает его.
Пример 3: self в декорированном методе (логирование вызовов)
import functools
def log_call(func):
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
print(f"Вызов {func.__name__} для {self}")
return func(self, *args, **kwargs)
return wrapper
class MyClass:
@log_call
def do_something(self, value):
self.value = value
obj = MyClass()
obj.do_something(42)
print(obj.value)
Вызов do_something для <__main__.MyClass object at 0x...> 42
Декоратор log_call принимает метод с первым параметром self, что позволяет получить доступ к экземпляру внутри обёртки.
Пример 4: 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("Радиус не может быть отрицательным")
self._radius = value
@property
def area(self):
return 3.14159 * self._radius ** 2
c = Circle(5)
print(c.radius, c.area)
c.radius = 10
print(c.area)
5 78.53975 314.159
Свойства (property) используют self для доступа к атрибутам экземпляра. Сеттер выполняет проверку перед изменением.
Пример 5: self в методе, возвращающем новый объект (неизменяемое копирование)
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def move(self, dx, dy):
return Point(self.x + dx, self.y + dy)
p1 = Point(0, 0)
p2 = p1.move(5, -3)
print(p2.x, p2.y) # 5 -3
5 -3
Метод move не изменяет исходный объект, а создаёт новый на основе self, что характерно для неизменяемых типов.