Модуль dataclasses предоставляет декоратор dataclass, который позволяет создавать data-классы - подобные позволяют значительно сократить шаблонный код классов. Как правило, такие классы предназначены для хранения некоторого состояния, некоторых данных и когда не требуется какое-то поведение в виде функций.
Рассмотрим простейший пример:
class Person: def __init__(self, name, age): self.name = name self.age = age tom = Person("Tom", 38) print(f"Name: {tom.name} Age: {tom.age}") # Name: Tom Age: 38
Здесь определен класс Person, у которого в функции конструктора определены два атрибута: name и age. Далее создаем один объект этого класса и выводим значения его атрибутов на консоль.
Теперь изменим эту программу, сделав класс Person data-классом:
from dataclasses import dataclass @dataclass class Person: name: str age: int tom = Person("Tom", 38) print(f"Name: {tom.name} Age: {tom.age}") # Name: Tom Age: 38
Для создания data-класса импортируем из модуля dataclasses декоратор dataclass и применяем его к классу Person. И в этом случае в самом классе нам уже не надо указывать конструктор - функцию
__init__
. Мы просто указываем атрибуты. А Python потом сам сгенерирует конструктор, в который также мы можем передать значения для атрибутов объекта.
Таким образом, мы уже сократили определение класса и сделали его более простым. Но генерацией метода __init__
функциональность декоратора dataclass не ограничивается. В реальности data-класс
@dataclass class Person: name: str age: int
будет аналогичен следующему:
class Person: def __init__(self, name, age): self.name = name self.age = age def __repr__(self): return f"Person(name={self.name!r}, age={self.age!r}" def __eq__(self, other): if other.__class__ is self.__class__: return (self.name, self.age) == (other.name, other.age) return NotImplemented
В данном случае мы видим, что кроме функции __init__, также определяется функция __repr__()
для возвращения строкового представления и функция __eq__()
для сравнения двух объектов. Применение данных функций:
from dataclasses import dataclass @dataclass class Person: name: str age: int tom = Person("Tom", 38) bob = Person("Bob", 42) tomas = Person("Tom", 38) print(tom == tomas) # True print(tom == bob) # False print(tom) # Person(name="Tom", age=38)
С помощью параметров декоратор dataclass
позволяет сгенерировать дополнительный шаблонный код и вообще настроить генерацию кода:
def dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False)
Рассмотрим базовые параметры:
init: если равно True
, то генерируется функция __init__()
. По умолчанию равно True
repr: если равно True
, то генерируется функция __repr__()
, которая возвращает строковое представление объекта.
По умолчанию равно True
eq: если равно True
, то генерируется функция __eq__()
, которая сравнивает два объекта.
По умолчанию равно True
order: если равно True
, то генерируются функции __lt__
(операция <),
__le__
(<=), __gt__
(>), __ge__
(>=), которые применяются для упорядочивания объектов.
По умолчанию равно False
unsafe_hash: если равно True
, то генерируется функция __hash__()
, которая возвращает хеш объекта.
По умолчанию равно False
Кроме того, те функции, которые создаются по умолчанию, могут быть переопределены.
Применение параметров:
from dataclasses import dataclass @dataclass(unsafe_hash=True, order=True) class Person: name: str age: int def __repr__(self): return f"Person. Name: {self.name} Age: {self.age}" tom = Person("Tom", 38) print(tom.__hash__()) # -421667297069596717 print(tom) # Person. Name: Tom Age: 38
В данном случае включаем генерирование хеша и функций упорядочивания, а также явным образом переопределяем функцию __repr__
для создания строкового представления объекта.
При необходимости атрибутам можно присвоить значения по умолчанию, если в конструкторе им не передаются значения:
from dataclasses import dataclass @dataclass class Person: name: str age: int = 18 tom = Person("Tom", 38) print(tom) # Person(name="Tom", age=38) bob = Person("Bob") print(bob) # Person(name="Bob", age=18)
Хотя data-классы предназначены прежде всего для хранения различных данных, но также в них можно определять поведение с помощью дополнительных функций:
from dataclasses import dataclass @dataclass class Person: name: str age: int def say_hello(self): print(f"{self.name} says hello") tom = Person("Tom", 38) tom.say_hello() # Tom says hello