Объект self: как работать с ним в методах
Основы работы с self
Ключевое слово self в Python представляет собой ссылку на текущий экземпляр класса. Оно используется в методах для доступа к атрибутам и другим методам этого экземпляра. Без self невозможно различить, с каким именно объектом работает метод. Рассмотрим наиболее эффективное и распространённое применение.
Самый распространённый способ - явно указать self первым параметром каждого метода экземпляра. Это позволяет обращаться к полям объекта через self.атрибут.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
return f"Меня зовут {self.name}, мне {self.age} лет."
p = Person("Анна", 25)
print(p.introduce())
атрибуты класса python (атрибуты классов и объектов в python)
Меня зовут Анна, мне 25 лет.
библиотека классов python (библиотека классов в python)
В конструкторе __init__ через self создаются атрибуты экземпляра. Метод introduce использует self.name и self.age для формирования строки. При вызове p.introduce() Python автоматически передаёт объект p в параметр self.
Типичная ошибка:
Забыть указатьself в определении метода. Это приводит к TypeError при вызове, так как метод получает лишний аргумент.
class Bad:
def method(): # нет self
print("Ошибка")
obj = Bad()
try:
obj.method()
except TypeError as e:
print(e)
метод объекта python (методы объектов в python)
method() takes 0 positional arguments but 1 was given
Python структура объекта (структура объекта в python)
Решение: всегда добавлять self как первый параметр в методы экземпляра.
Как использовать другое имя вместо self?
Python не требует строго имени self. Можно использовать любое другое (например, this, me). Однако это нарушает общепринятые соглашения (PEP 8) и делает код менее читаемым.
class Example:
def __init__(this, value): # нестандартное имя
this.value = value
def show(me):
return me.value
e = Example(42)
print(e.show())
Python создание объектов (создание объектов в python)
42
Self object python (объект self в python)
Код работает, но его сложнее понимать другим разработчикам. Рекомендуется придерживаться self.
Как организовать работу с методами, не требующими экземпляра?
Иногда метод не использует self - например, для служебной логики, не зависящей от объекта. В таких случаях применяются staticmethod и classmethod.
Что такое метод класса (classmethod)?
Метод класса принимает первым параметром сам класс (cls), а не экземпляр. Он помещается декоратором @classmethod.
class MyClass:
count = 0
def __init__(self):
MyClass.count += 1
@classmethod
def get_count(cls):
return cls.count
obj1 = MyClass()
obj2 = MyClass()
print(MyClass.get_count())
Object attribute python (атрибуты объекта в python)
2
Python call method (вызов метода в python)
Здесь cls - это сам класс MyClass. Метод get_count вызывается как MyClass.get_count() или даже obj1.get_count(), но в обоих случаях первым аргументом передаётся класс.
Как объявить статический метод (staticmethod)?
Статический метод не принимает ни self, ни cls. Он ведёт себя как обычная функция, но лежит в пространстве имён класса.
class MathUtils:
@staticmethod
def add(a, b):
return a + b
print(MathUtils.add(3, 4))
Python класс данных (класс данных в python)
7
Class method python (методы классов в python)
Статические методы удобны для вспомогательных операций, не зависящих от состояния объекта.
Как получить доступ к экземпляру из метода без явного self?
В Python, в отличие от Java или C++, не существует неявного this. Для доступа к текущему объекту необходимо явно использовать первый параметр. Однако можно вызывать методы, передавая экземпляр как обычный аргумент:
class A:
def method(self):
print("Метод вызван")
a = A()
A.method(a) # явная передача экземпляра
Python object methods (методы объектов в python)
Метод вызван
класс python определение (определение классов в python)
Этот приём иногда помогает лучше понять, как работает передача self, но на практике обычно используется запись a.method().
Проблема с изменяемыми атрибутами:
Если атрибут является изменяемым объектом (список, словарь), его изменение черезself влияет на экземпляр. Это ожидаемо, но иногда приводит к путанице.
class Stack:
def __init__(self):
self.items = []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
s = Stack()
s.push(1)
s.push(2)
print(s.pop())
Self method python (параметр self в методах python)
2
приватные атрибуты python (приватные атрибуты в python)
Ошибок нет, но если по ошибке присвоить self.items = self.items + [item] - создастся новый список, а не модифицируется существующий. Важно различать мутацию и переназначение.
Когда self не нужен?
В некоторых специальных методах, таких как __new__, self не передаётся, потому что экземпляр ещё не создан. Вместо этого используется cls. А в статических и классовых методах, как уже обсуждалось, self отсутствует по определению.
Ошибка при попытке использовать self в статическом методе:
При добавленииself в статический метод Python не вызовет ошибку автоматически, но это нарушает соглашения. Если такой метод всё же определён с self, он станет обычным методом экземпляра, что может привести к неожиданностям.
class Wrong:
@staticmethod
def method(self): # неправильное использование
print(self)
w = Wrong()
try:
w.method()
except TypeError as e:
print(e)
создание типов python (создание пользовательских типов данных в python)
method() got multiple values for argument 'self'
Здесь декоратор @staticmethod игнорирует self как первый параметр, но при вызове через экземпляр Python пытается передать объект дважды (явно и неявно). Нужно либо убрать self, либо не вешать декоратор.
Расширенные примеры работы с self
1. Использование self в магическом методе __repr__
Метод __repr__ возвращает строковое представление объекта. Через self можно получать значения атрибутов для отладки.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point(x={self.x}, y={self.y})"
p = Point(3, 4)
print(p)
Point(x=3, y=4)
2. Цепочка вызовов методов через возврат self
Если метод возвращает self, можно вызывать несколько методов подряд (fluent interface).
class Query:
def __init__(self):
self._conditions = []
def filter(self, condition):
self._conditions.append(condition)
return self
def sort(self, key):
self._sort_key = key
return self
def execute(self):
return f"Сортировка: {getattr(self, '_sort_key', 'нет')}, фильтры: {self._conditions}"
q = Query()
result = q.filter("age > 18").sort("name").execute()
print(result)
Сортировка: name, фильтры: ['age > 18']
3. Получение класса экземпляра через self.__class__
Атрибут self.__class__ возвращает класс объекта. Это полезно для создания копий или доступа к классовым атрибутам.
class Car:
wheels = 4
def info(self):
return f"Это {self.__class__.__name__} с {self.wheels} колёсами"
class Truck(Car):
wheels = 6
c = Car()
t = Truck()
print(c.info())
print(t.info())
Это Car с 4 колёсами Это Truck с 6 колёсами
4. Применение self в дескрипторах для доступа к атрибутам
Дескриптор - объект, который управляет доступом к атрибуту. Методы __get__, __set__ принимают self (сам дескриптор) и instance (экземпляр, к атрибуту которого обращаются).
class PositiveNumber:
def __init__(self, name):
self.name = name
def __get__(self, instance, owner):
return instance.__dict__.get(self.name)
def __set__(self, instance, value):
if value < 0:
raise ValueError("Значение должно быть положительным")
instance.__dict__[self.name] = value
class Order:
quantity = PositiveNumber("quantity")
def __init__(self, quantity):
self.quantity = quantity
o = Order(10)
print(o.quantity)
try:
o.quantity = -5
except ValueError as e:
print(e)
10 Значение должно быть положительным
5. self в методе __init__subclass__ для проверки подклассов
Метаклассы и хуки создания классов используют cls, но иногда через self (точнее, через экземпляр) можно получить доступ к метаклассу. Более показательный пример - использование self в магическом методе __init_subclass__, который вызывается при создании подкласса. Он принимает cls, но внутри может обращаться к super().__init_subclass__, где нет self. Однако рассмотрим другой случай: метод __del__, который вызывается при удалении объекта.
class Resource:
def __init__(self):
self.handle = open("/dev/null", "w")
def __del__(self):
self.handle.close()
print("Ресурс освобождён")
r = Resource()
del r
Ресурс освобождён
6. Создание синглтона через self и __new__
Метод __new__ создаёт экземпляр, получая первым аргументом класс (cls), а не self. Однако внутри __new__ можно управлять тем, какой объект вернуть. Классический синглтон:
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
self.value = 0
a = Singleton()
b = Singleton()
print(a is b) # True
True