Введение
В этой лабораторной работе вы познакомитесь с Python Dataclasses (классами данных Python) — мощной функцией, доступной начиная с Python 3.7. Dataclasses — это обычные классы Python, которые в основном используются для хранения данных. Они используют декоратор @dataclass для автоматической генерации специальных методов, таких как __init__() и __repr__(), что значительно сокращает шаблонный код (boilerplate code).
В ходе этой лабораторной работы вы научитесь:
- Определять простой dataclass.
- Сравнивать его с реализацией на стандартном классе.
- Устанавливать значения по умолчанию для полей.
- Работать с подсказками типов (type hints), включая использование
typing.Any.
К концу этой лабораторной работы вы сможете писать более чистые и лаконичные классы, ориентированные на данные, на Python.
Возможности Dataclass
На этом шаге вы изучите основные возможности классов данных (dataclasses). Мы начнем с рассмотрения стандартного класса Python для хранения данных, а затем увидим, как dataclass упрощает этот процесс.
Стандартный класс требует ручного написания метода __init__ для инициализации атрибутов.
Например, класс для представления числа будет выглядеть так:
class Number:
def __init__(self, val):
self.val = val
obj = Number(2)
print(obj.val)
С помощью декоратора @dataclass Python автоматически генерирует метод __init__, а также другие полезные методы, такие как __repr__ для чистого строкового представления. Основное требование — вы должны предоставить подсказки типов (type hints) для полей.
Примечание: Если вы не знакомы с использованием WebIDE (подобной VS Code), пожалуйста, изучите это в этой лаборатории.
Давайте создадим тот же класс Number, используя декоратор @dataclass.
Откройте файл features.py в проводнике файлов слева. Добавьте в него следующий код:
from dataclasses import dataclass
@dataclass ## Этот декоратор преобразует класс в dataclass
class Number:
val: int ## Подсказка типа обязательна
## Метод __init__ создается автоматически
obj = Number(2)
## Вывод значения атрибута 'val'
print(obj.val)
## Метод __repr__ также создается автоматически, обеспечивая аккуратное представление
print(obj)
Теперь запустите скрипт из терминала, чтобы увидеть вывод.
python3 features.py
Вы увидите следующий вывод. Первая строка — это значение атрибута, а вторая строка — чистое представление объекта, предоставляемое автоматически сгенерированным методом __repr__.
2
Number(val=2)
Как видите, версия с dataclass более лаконична и требует меньше шаблонного кода (boilerplate code).
Использование значений по умолчанию
На этом шаге вы узнаете, как добавлять значения по умолчанию (default values) полям класса данных (dataclass). Это распространенное требование, когда некоторые атрибуты являются необязательными.
Важное правило, которое следует запомнить: любое поле со значением по умолчанию должно быть объявлено после всех полей без значений по умолчанию.
Давайте создадим dataclass Product, где name является обязательным полем, а count и price — необязательными и имеют значения по умолчанию.
Откройте файл defaults.py в проводнике файлов. Добавьте в него следующий код:
from dataclasses import dataclass
@dataclass
class Product:
name: str ## Обязательное поле
count: int = 0 ## Необязательное поле со значением по умолчанию
price: float = 0.0 ## Необязательное поле со значением по умолчанию
## Создаем экземпляр, предоставляя только обязательное поле 'name'
obj = Product("Python")
## Выводим атрибуты, чтобы увидеть, как работают значения по умолчанию
print(f"Name: {obj.name}")
print(f"Count: {obj.count}")
print(f"Price: {obj.price}")
Теперь выполните скрипт в терминале.
python3 defaults.py
Вывод покажет, что полям count и price были автоматически присвоены их значения по умолчанию.
Name: Python
Count: 0
Price: 0.0
Эта функция делает создание объектов с необязательными атрибутами очень удобным.
Обработка подсказок типов (Type Hints)
На этом шаге вы поймете требование использования подсказок типов в классах данных (dataclasses). Как вы уже видели, указание типа для каждого поля является обязательным при определении dataclass.
Однако могут возникнуть ситуации, когда вы не хотите или не можете указать конкретный тип данных для поля. Для таких случаев модуль typing Python предоставляет специальный тип под названием Any. Использование Any сообщает проверщику типов (type checker), что значение может быть любого типа.
Давайте создадим dataclass, в котором мы используем Any для полей.
Откройте файл type_hints.py в проводнике файлов и добавьте следующий код:
from dataclasses import dataclass
from typing import Any
@dataclass
class WithoutExplicitTypes:
name: Any
value: Any = 42
## Создаем экземпляр, где 'name' — строка. 'value' использует значение по умолчанию.
obj1 = WithoutExplicitTypes(name="Test")
print(f"Object 1: name={obj1.name}, value={obj1.value}")
## Создаем другой экземпляр, где 'name' — целое число, а 'value' — строка.
obj2 = WithoutExplicitTypes(name=123, value="hello")
print(f"Object 2: name={obj2.name}, value={obj2.value}")
Теперь запустите скрипт из терминала.
python3 type_hints.py
Вы увидите следующий вывод, демонстрирующий, что поля могут содержать значения разных типов.
Object 1: name=Test, value=42
Object 2: name=123, value=hello
Хотя Any обеспечивает гибкость, в целом хорошей практикой является использование конкретных типов всякий раз, когда это возможно, чтобы сделать ваш код более надежным и самодокументируемым.
Резюме
В этой лабораторной работе вы узнали, как использовать классы данных (dataclasses) Python для создания лаконичных и читаемых классов, ориентированных на данные.
Вы рассмотрели следующие ключевые концепции:
- Декоратор
@dataclassавтоматически генерирует специальные методы, такие как__init__()и__repr__(), что уменьшает количество шаблонного кода (boilerplate code). - Как определять поля со значениями по умолчанию, и правило, согласно которому они должны следовать за полями без значений по умолчанию.
- Обязательный характер подсказок типов (type hints) в dataclasses и как использовать
typing.Anyдля полей, для которых не требуется определенный тип.
Dataclasses являются мощным инструментом в современном Python для написания чистого, поддерживаемого и эффективного кода, особенно при работе с классами, которые в основном хранят состояние (state).



