Объявление классов в объектно-ориентированном программировании Python

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

Определение классов в Python

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

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

Пример простого класса Person с именем и возрастом:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def greet(self):
        return f"Привет, меня зовут {self.name}"

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

Метод __init__ вызывается при создании экземпляра и принимает аргументы, которые присваиваются атрибутам. Параметр self ссылается на конкретный объект. Любой метод экземпляра первым аргументом получает self.

Использование:

p = Person("Анна", 25)
print(p.greet())  # Привет, меня зовут Анна

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

Типичные ошибки: забыть указать self в определении метода (вызовет TypeError при попытке вызвать метод), или неправильно передать аргументы в конструктор. Также часто путают атрибуты экземпляра и класса: если написать name = "" внутри тела класса, это атрибут класса, а не экземпляра.

Как автоматически создавать атрибуты с помощью dataclass?

Модуль dataclasses (Python 3.7+) упрощает объявление классов, которые в основном хранят данные. Декоратор @dataclass автоматически генерирует __init__, __repr__, __eq__ и другие методы.

Цель: сократить шаблонный код при работе с простыми контейнерами данных. Случай использования: модель данных, конфигурация, DTO (Data Transfer Object).

from dataclasses import dataclass

@dataclass
class Point:
    x: float
    y: float

p1 = Point(1.5, 2.0)
p2 = Point(1.5, 2.0)
print(p1)        # Point(x=1.5, y=2.0)
print(p1 == p2)  # True

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

Поля можно снабжать значениями по умолчанию, валидировать с помощью __post_init__. Недостаток: классы dataclass по умолчанию изменяемы; для неизменяемых объектов нужно указать frozen=True.

Проблема: если в поле используется изменяемое значение по умолчанию (например, пустой список), все экземпляры разделяют один список. Решение: использовать field(default_factory=list).

Как добавить свойства (property) для контролируемого доступа к атрибутам?

Декоратор @property позволяет определить метод, который будет вызываться при обращении к атрибуту, как если бы это был обычный атрибут. Это используется для валидации, вычисляемых значений или создания read-only интерфейса.

Пример класса Temperature:

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

    @property
    def celsius(self):
        return self._celsius

    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("Температура ниже абсолютного нуля")
        self._celsius = value

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

t = Temperature(25)
print(t.fahrenheit)  # 77.0
t.celsius = 30
print(t.fahrenheit)  # 86.0

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

Случай использования: когда необходимо добавить логику чтения/записи без изменения публичного интерфейса (принцип единого доступа).

Ошибка: забыть указать @property над геттером, тогда вызов obj.celsius вернёт объект метода, а не значение. Также нельзя использовать property как декоратор для сеттера без геттера.

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

Наследование позволяет создать класс на основе другого, унаследовав его атрибуты и методы. Ключевое слово super() используется для вызова методов родительского класса.

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

    def speak(self):
        return "..."

class Dog(Animal):
    def speak(self):
        return "Гав!"

class Cat(Animal):
    def __init__(self, name, color):
        super().__init__(name)
        self.color = color

    def speak(self):
        return "Мяу!"

dog = Dog("Барсик")
cat = Cat("Мурка", "серый")
print(dog.speak())  # Гав!
print(cat.speak())  # Мяу!
print(cat.name)     # Мурка

Наследование полезно для создания иерархий классов, избегания дублирования кода и реализации полиморфизма.

Проблемы: множественное наследование может вызвать конфликт имён (ромбовидное наследование). Для разрешения используется MRO (Method Resolution Order). Часто вместо множественного наследования применяют композицию или миксины.

- Self object python (объект self в python)
- Object attribute python (атрибуты объекта в python)
- Python call method (вызов метода в python)

Расширенные примеры определения классов

Класс-метод и статический метод

Декоратор @classmethod создаёт метод, который получает первым аргументом сам класс (cls), а не экземпляр. Используется для фабричных методов.

Пример
class Book:
    def __init__(self, title, pages):
        self.title = title
        self.pages = pages

    @classmethod
    def create_from_dict(cls, data):
        return cls(data['title'], data['pages'])

    @staticmethod
    def is_valid_title(title):
        return len(title) > 0 and title[0].isupper()

book = Book.create_from_dict({'title': '1984', 'pages': 328})
print(book.title)  # 1984
print(Book.is_valid_title('1984'))  # True
1984
True

Статический метод (@staticmethod) не получает ни self, ни cls; он ведёт себя как обычная функция, находящаяся в пространстве имён класса.

Перегрузка операторов и магические методы

Методы __add__, __str__, __repr__ и другие позволяют переопределить поведение операторов.

Пример
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})"

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

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

Также можно реализовать __call__ для возможности вызывать объект как функцию, __iter__ и __next__ для итераторов.

Контекстный менеджер через __enter__ и __exit__

Пример
class ManagedFile:
    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_val, exc_tb):
        if self.file:
            self.file.close()

with ManagedFile('test.txt') as f:
    f.write('Hello, world!')
# файл автоматически закрыт

Случаи использования: работа с файлами, сетевыми подключениями, блокировками.

Дескрипторы (descriptors)

Дескрипторы реализуют протокол с методами __get__, __set__, __delete__ и позволяют управлять доступом к атрибутам на уровне класса.

Пример
class PositiveNumber:
    def __set_name__(self, owner, name):
        self.name = name

    def __get__(self, obj, objtype=None):
        return obj.__dict__.get(self.name)

    def __set__(self, obj, value):
        if value <= 0:
            raise ValueError("Значение должно быть положительным")
        obj.__dict__[self.name] = value

class Order:
    quantity = PositiveNumber()
    price = PositiveNumber()

    def __init__(self, quantity, price):
        self.quantity = quantity
        self.price = price

order = Order(10, 150.0)
print(order.quantity)  # 10
# order.quantity = -5  # ValueError
10

Абстрактные классы (ABC)

Модуль abc позволяет создавать классы, которые нельзя инстанцировать, и заставлять подклассы реализовывать определённые методы.

Пример
from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

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

    def area(self):
        return 3.14159 * self.radius ** 2

# shape = Shape()  # TypeError: Can't instantiate abstract class
circle = Circle(5)
print(circle.area())  # 78.53975
78.53975

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

Слоты (__slots__) для экономии памяти

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

p = Point(1, 2)
# p.z = 3  # AttributeError: 'Point' object has no attribute 'z'

Слоты фиксируют набор допустимых атрибутов, уменьшают потребление памяти и ускоряют доступ к атрибутам. Используются при создании тысяч объектов, например, в играх или научных вычислениях.

Определение классов в Python - comments

En
класс python определение (python)