Методы в языке Python: полное руководство

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

Определение методов в Python

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

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

    def show_value(self):
        print(f"Значение: {self.value}")

obj = MyClass(42)
obj.show_value()  # Вывод: Значение: 42

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

Значение: 42

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

Параметр self автоматически передается при вызове метода через экземпляр. Важно не забывать указывать его в определении, иначе возникнет ошибка при вызове.

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

Для методов, которые работают с атрибутами класса, а не экземпляра, применяется декоратор @classmethod. Первый аргумент такого метода - cls (ссылка на класс).

class MyClass:
    class_attribute = 0

    @classmethod
    def increment_class_attr(cls):
        cls.class_attribute += 1
        return cls.class_attribute

print(MyClass.increment_class_attr())  # 1
print(MyClass.increment_class_attr())  # 2

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

1
2

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

Важно:

Методы класса могут быть вызваны как от класса, так и от экземпляра, но при вызове от экземпляра все равно первым аргументом будет класс.

Как создать вспомогательную функцию внутри класса, не зависящую от объекта?

Для функций, которые логически принадлежат классу, но не требуют доступа ни к экземпляру, ни к классу, используется декоратор @staticmethod. Они ведут себя как обычные функции, но размещены в пространстве имен класса.

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

    @staticmethod
    def multiply(a, b):
        return a * b

print(MathUtils.add(5, 3))       # 8
print(MathUtils.multiply(4, 2)) # 8

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

8
8

Self object python (объект self в python)

Как сделать метод, который ведет себя как атрибут (геттер/сеттер)?

Декоратор @property позволяет определить метод, который вызывается при обращении к атрибуту без круглых скобок. Для записи значения используются сеттеры с @attribute.setter, для удаления - @attribute.deleter.

class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius

    @property
    def fahrenheit(self):
        return (self._celsius * 9/5) + 32

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

t = Temperature(0)
print(t.fahrenheit)  # 32.0
t.fahrenheit = 100
print(t._celsius)    # 37.7777...

Object attribute python (атрибуты объекта в python)

32.0
37.77777777777778

Python call method (вызов метода в python)

Как определить абстрактный метод, который должен быть переопределен в подклассах?

Используя модуль abc и декоратор @abstractmethod, можно создавать абстрактные базовые классы. Такие методы не имеют реализации в базовом классе и обязаны быть переопределены в производных классах.

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def sound(self):
        pass

class Dog(Animal):
    def sound(self):
        return "Woof"

# animal = Animal() - ошибка
dog = Dog()
print(dog.sound())  # Woof

Python класс данных (класс данных в python)

Woof

Class method python (методы классов в python)

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

Методы с двойными подчеркиваниями (dunder) позволяют объектам поддерживать встроенные операции. Например, __add__ для сложения, __len__ для длины.

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 __repr__(self):
        return f"Vector({self.x}, {self.y})"

v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2
print(v3)  # Vector(4, 6)

Python object methods (методы объектов в python)

Vector(4, 6)

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

  • Забыли self: При определении метода экземпляра без self вызов приведет к ошибке TypeError: method() takes 0 positional arguments but 1 was given. Решение - всегда добавлять self первым параметром.
  • Перепутали self и cls: В методах класса вместо self используется cls. Если в @classmethod написать self, работать будет, но это введет в заблуждение. Лучше придерживаться соглашения.
  • Вызов метода класса через экземпляр: Хотя это работает, лучше вызывать метод класса от имени класса, чтобы подчеркнуть его природу.
  • Не использовать @property для геттеров: Если метод не требует аргументов и просто возвращает вычисленное значение, лучше использовать свойство, а не обычный метод.
  • Ошибка при определении абстрактного метода без наследования от ABC: Декоратор @abstractmethod работает только внутри класса, наследующего от ABC. Иначе абстрактность не будет принудительно проверяться.
- приватные атрибуты python (приватные атрибуты в python)
- создание типов python (создание пользовательских типов данных в python)
- тип данных класса python (тип данных класса в python)
Пример
# Пример 1: Метод с переменным числом аргументов
class Calculator:
    def add(self, *args):
        return sum(args)

calc = Calculator()
print(calc.add(1,2,3,4))  # 10
10
Пример
# Пример 2: Fluent interface - метод возвращает self
class Builder:
    def __init__(self):
        self.result = []
    def add_item(self, item):
        self.result.append(item)
        return self
    def build(self):
        return self.result

b = Builder().add_item(1).add_item(2).add_item(3).build()
print(b)  # [1,2,3]
[1, 2, 3]
Пример
# Пример 3: Метод, используемый как декоратор (callable class)
class CountCalls:
    def __init__(self, func):
        self.func = func
        self.calls = 0
    def __call__(self, *args, **kwargs):
        self.calls += 1
        print(f"Вызов {self.calls}: {self.func.__name__}")
        return self.func(*args, **kwargs)

@CountCalls
def say_hello():
    print("Hello!")

say_hello()  # Вызов 1: say_hello / Hello!
say_hello()  # Вызов 2: say_hello / Hello!
Вызов 1: say_hello
Hello!
Вызов 2: say_hello
Hello!
Пример
# Пример 4: Методы с аннотациями типов и проверкой
class Point:
    def __init__(self, x: float, y: float) -> None:
        self.x = x
        self.y = y
    def distance_to(self, other: 'Point') -> float:
        import math
        return math.hypot(self.x - other.x, self.y - other.y)

p1 = Point(0,0)
p2 = Point(3,4)
print(p1.distance_to(p2))  # 5.0
5.0
Пример
# Пример 5: Дескрипторы с методами __get__, __set__, __delete__
class ValidatedAttribute:
    def __init__(self, validator):
        self.validator = validator
        self.data = {}
    def __get__(self, obj, objtype):
        if obj is None:
            return self
        return self.data.get(id(obj), None)
    def __set__(self, obj, value):
        if self.validator(value):
            self.data[id(obj)] = value
        else:
            raise ValueError(f"Некорректное значение: {value}")

class Person:
    age = ValidatedAttribute(lambda v: 0 <= v <= 150)
    def __init__(self, name, age):
        self.name = name
        self.age = age  # вызовет сеттер

p = Person("Alice", 30)
print(p.age)  # 30
# p.age = 200  # ValueError
30
Пример
# Пример 6: Итератор с методами __iter__ и __next__
class CountDown:
    def __init__(self, start):
        self.current = start
    def __iter__(self):
        return self
    def __next__(self):
        if self.current < 0:
            raise StopIteration
        value = self.current
        self.current -= 1
        return value

for num in CountDown(5):
    print(num, end=' ')  # 5 4 3 2 1 0
5 4 3 2 1 0
Пример
# Пример 7: Контекстный менеджер с методами __enter__ и __exit__
class FileManager:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.file.close()

with FileManager('test.txt', 'w') as f:
    f.write('Hello')

# после with файл закрыт
(файл test.txt создан, содержимое "Hello")
Пример
# Пример 8: Метод __call__ для создания функционального объекта
class Multiplier:
    def __init__(self, factor):
        self.factor = factor
    def __call__(self, x):
        return x * self.factor

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

Определение методов в Python - comments

En
Python определение методов (python)