Виды методов Python: от базовых до магических

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

Основное решение: определение и вызов методов

Метод - это функция, определённая внутри класса и предназначенная для работы с данными этого класса. В Python существует три основных типа методов: экземпляра, класса и статические. Наиболее универсальный - метод экземпляра. Пример:

class Counter:
    def __init__(self, start=0):
        self.value = start
    def increment(self, step=1):
        self.value += step
        return self.value
c = Counter()
print(c.increment())  # 1
print(c.increment(5)) # 6

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

Этот подход эффективен, так как метод имеет доступ к атрибутам экземпляра через self и может модифицировать состояние объекта.

Как определить метод экземпляра?

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

class Student:
    def __init__(self, name, grade):
        self.name = name
        self.grade = grade
    def promote(self):
        self.grade += 1
        return self.grade
s = Student("Иван", 9)
print(s.promote())  # 10

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

Типичная ошибка - забыть указать self в определении. Тогда при вызове от экземпляра возникнет TypeError с сообщением, что метод не принимает аргументов, но был передан self автоматически.

Когда следует применять метод класса?

Метод класса декорируется @classmethod и принимает cls (сам класс). Он полезен для создания альтернативных конструкторов или операций, не зависящих от конкретного экземпляра:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    @classmethod
    def square(cls, side):
        return cls(side, side)
r = Rectangle.square(5)
print(r.width, r.height)  # 5 5

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

Распространённая путаница: отсутствие декоратора @classmethod превращает cls в обычный параметр, и вызов через класс приведёт к передаче класса как аргумента, что нарушит логику.

Для чего используются статические методы?

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

class StringUtils:
    @staticmethod
    def is_palindrome(s):
        return s == s[::-1]
print(StringUtils.is_palindrome("level"))  # True

метод call python (метод __call__ в python)

Новички часто пытаются через статический метод получить доступ к атрибутам класса или экземпляра, что невозможно без передачи их явно. В таких случаях нужен метод класса или экземпляра.

Какие магические методы стоит знать?

Магические методы (с двойными подчёркиваниями) переопределяют стандартное поведение объектов. Например, __str__ отвечает за строковое представление, __len__ - за длину, __add__ - за сложение:

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
    def __str__(self):
        return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2)  # Vector(4, 6)

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

Ошибка - забыть вернуть новый объект в __add__ или изменить текущий. Метод должен возвращать новый экземпляр, а не None или self без изменений.

Как работают свойства (property)?

Декоратор @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
c = Circle(5)
c.radius = 10  # работает
print(c.radius)  # 10

Python создание объектов (создание объектов в python)

Если не определить сеттер, попытка присвоить значение атрибуту вызовет AttributeError с сообщением, что свойство только для чтения.

Какие встроенные методы есть у строк и списков?

Встроенные типы данных обладают богатым набором методов. Строки предоставляют методы .upper(), .split(), .join() и другие. Списки - .append(), .pop(), .sort():

text = " hello world "
print(text.strip().upper())  # HELLO WORLD

nums = [3, 1, 4, 1, 5]
nums.sort()
print(nums)  # [1, 1, 3, 4, 5]

Важно помнить, что строки неизменяемы - все методы возвращают новую строку, не меняя исходную. Списки же изменяются на месте (например, .sort() возвращает None).

- Python call method (вызов метода в python)
- Python класс данных (класс данных в python)
- Class method python (методы классов в python)

Практические примеры с подробными пояснениями

Цепочка методов (fluent interface)

Метод может возвращать self, позволяя вызывать несколько методов подряд:

Пример
class TextProcessor:
    def __init__(self, text):
        self.text = text
    def remove_punctuation(self):
        import string
        self.text = ''.join(ch for ch in self.text if ch not in string.punctuation)
        return self
    def to_uppercase(self):
        self.text = self.text.upper()
        return self
    def get_result(self):
        return self.text

tp = TextProcessor("Hello, World!")
result = tp.remove_punctuation().to_uppercase().get_result()
print(result)
HELLO WORLD

Такой подход удобен для построения пайпов обработки данных.

Альтернативный конструктор через classmethod

Класс может предоставлять фабричные методы, создающие объекты разными способами:

Пример
class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day
    @classmethod
    def from_string(cls, date_str, delimiter='-'):
        parts = date_str.split(delimiter)
        return cls(int(parts[0]), int(parts[1]), int(parts[2]))
    def __repr__(self):
        return f"Date({self.year}, {self.month}, {self.day})"

d = Date.from_string("2024-07-21")
print(d)
Date(2024, 7, 21)

Метод класса from_string берёт на себя разбор строки и возвращает новый экземпляр.

Статический метод для валидации

Статические методы хорошо подходят для проверки входных данных перед созданием объекта:

Пример
class User:
    def __init__(self, email):
        if not self.is_valid_email(email):
            raise ValueError("Некорректный email")
        self.email = email
    @staticmethod
    def is_valid_email(email):
        return '@' in email and '.' in email.split('@')[-1]

try:
    u = User("test@example.com")
    print("Пользователь создан")
    u2 = User("invalid")
except ValueError as e:
    print(e)
Пользователь создан
Некорректный email

Валидация вынесена в статический метод, что делает её независимой и тестируемой.

Магический метод __call__ для вызываемых объектов

Объект можно сделать вызываемым, определив __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), triple(5))
10 15

Такие объекты удобны для хранения состояния вместе с логикой вызова (замыкания с параметрами).

Свойство с сеттером и валидацией

Пример свойства, которое контролирует устанавливаемое значение:

Пример
class Person:
    def __init__(self, age):
        self._age = None
        self.age = age  # используем сеттер
    @property
    def age(self):
        return self._age
    @age.setter
    def age(self, value):
        if not (0 <= value <= 120):
            raise ValueError("Возраст вне допустимого диапазона")
        self._age = value

p = Person(25)
print(p.age)  # 25
try:
    p.age = -5
except ValueError as e:
    print(e)
25
Возраст вне допустимого диапазона

Сеттер позволяет выполнять проверки при каждом присвоении.

Дескриптор с методами __get__ и __set__

Дескрипторы управляют доступом к атрибутам на уровне класса:

Пример
class PositiveNumber:
    def __set_name__(self, owner, name):
        self.private_name = '_' + name
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return getattr(obj, self.private_name, 0)
    def __set__(self, obj, value):
        if value <= 0:
            raise ValueError("Значение должно быть положительным")
        setattr(obj, self.private_name, value)

class Order:
    quantity = PositiveNumber()
    price = PositiveNumber()
    def __init__(self, quantity, price):
        self.quantity = quantity
        self.price = price
    def total(self):
        return self.quantity * self.price

order = Order(2, 150.0)
print(order.total())  # 300.0
try:
    order.quantity = -1
except ValueError as e:
    print(e)
300.0
Значение должно быть положительным

Дескрипторы полезны для повторного использования логики валидации в разных классах.

Полиморфизм методов - единый интерфейс

Разные классы могут реализовывать метод с одним именем, что позволяет обрабатывать их единообразно:

Пример
class Dog:
    def sound(self):
        return "Гав"
class Cat:
    def sound(self):
        return "Мяу"
class Cow:
    def sound(self):
        return "Муу"

animals = [Dog(), Cat(), Cow()]
for animal in animals:
    print(animal.sound())
Гав
Мяу
Муу

Полиморфизм позволяет писать код, работающий с любым объектом, поддерживающим нужный метод.

Методы в Python - comments

En
какие есть методы в python (python)