from dataclasses import dataclass @dataclass(*, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False, weakref_slot=False) class MyType: ...
init=True
- флаг для создания метода __init__()
,repr=True
- флаг для создания метода __repr__()
,eq=True
- флаг для создания метода __eq__()
,order=False
- флаг для создания методов сравнения класса, unsafe_hash=False
- флаг для создания метода __hash__()
,frozen=False
- флаг для создания неизменяемого типа,match_args=True
- создает кортеж __match_args__
из списка аргументов (добавлено в Python 3.10),kw_only=False
- помечает все поля класса как содержащие только ключевые слова (добавлено в Python 3.10),slots=False
- если True
, то генерирует атрибут __slots__
(добавлено в Python 3.10),weakref_slot=False
- добавляет слот с именем __weakref__
(добавлено в Python 3.11).Функция dataclass()
модуля dataclasses
является декоратором, который используется для добавления сгенерированных специальных методов к классам, как описано ниже.
Декоратор @dataclass()
ищет поля, имеющие аннотацию типа и определяет их как переменные класса, за двумя исключениями, описанными ниже.
Декоратор @dataclass()
не проверяет, указанный в аннотации, тип переменной!
Порядок полей во всех сгенерированных методах - это порядок, в котором они появляются в определении класса.
Декоратор @dataclass()
добавит к классу различные "dunder" методы, описанные ниже. Если какой-либо из добавленных методов уже существует в классе, то поведение зависит от параметра, как описано ниже. Декоратор возвращает тот же класс, который вызывается, новый класс не создается.
Если dataclasses.dataclass()
используется как простой декоратор без параметров, то он действует так, как если бы он имел значения по умолчанию. То есть эти три варианта использования @dataclass()
эквивалентны:
from dataclasses import dataclass @dataclass class C: ... @dataclass() class C: ... @dataclass(*, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False) class C: ...
Поведение декоратора @dataclass()
в зависимости от значений аргументов:
init
: если True
(по умолчанию), то будет создан метод __init__()
.
Если класс уже имеет метод __init__()
, этот параметр игнорируется.
repr
: если True
(по умолчанию), будет сгенерирован метод __repr__()
. Сгенерированная строка будет иметь имя класса, а также имя и repr
каждого поля в том порядке, в котором они определены в классе. Поля, отмеченные как исключенные, не включаются.
Например: InventoryItem(name = 'widget', unit_price = 3.0, quantity_on_hand = 10)
.
Если класс уже имеет метод __repr__()
, этот параметр игнорируется.
eq
: если True
(по умолчанию), будет создан метод __eq__()
. Этот метод сравнивает класс по порядку, как если бы он был кортежем его полей. Оба экземпляра в сравнении должны быть одного типа.
Если класс уже имеет метод __eq__()
, этот параметр игнорируется.
order
: если True
(по умолчанию False
), будут созданы методы __lt__()
, __le__()
, __gt__()
и __ge__()
. Они по порядку сравнивают класс, как если бы он был кортежем его полей. Оба экземпляра в сравнении должны быть одного типа.
Если order
равен True
, а eq
- false, возникает ошибка ValueError.
Если класс уже определяет какое-либо из __lt__()
, __le__()
, __gt__()
или __ge__()
, возникает ошибка TypeError
.
unsafe_hash
: если False
(по умолчанию), то метод __hash__()
создается в соответствии с тем, как установлены аргументы eq
и frozen
.
Метод __hash__()
используется встроенной функцией hash()
и когда объекты добавляются в хешированные коллекции, такие как словари и множества. Наличие метода __hash__()
подразумевает, что экземпляры класса неизменяемы. Изменяемость - это сложное свойство, которое зависит от намерений программиста, существования и поведения метода __eq__()
, а также значений флагов eq
и frozen
в декораторе @dataclass()
.
По умолчанию @dataclass()
не будет неявно добавлять метод __hash__()
, если это не безопасно. Он также не будет добавлять или изменять существующий явно определенный метод __hash__()
. Установка атрибута класса __hash__= None
имеет особое значение для Python, как описано в документации __hash__()
.
Если метод __hash__()
не определен явно или если для него установлено значение None
, то тогда @dataclass()
может добавить неявный метод __hash__()
. Хотя это не рекомендуется, можно заставить @dataclass()
создать метод __hash__()
с unsafe_hash=True
. Это может быть так, если класс логически неизменен, но, тем не менее, может быть изменен. Это особый вариант использования, который следует тщательно продумать.
Вот правила, регулирующие неявное создание метода __hash__()
:
__hash__()
в классе данных и установить аргумент unsafe_hash=True
. Это приведет к ошибке TypeError
.eq
и frozen
имеют значение True
, то по умолчанию декоратор @dataclass()
сгенерирует метод __hash__()
. eq=True
, а frozen=False
, то __hash__()
будет установлен в None
, помечая его как не хешируемый (что так и есть, поскольку оно изменяемое). eq=False
, то __hash__()
останется нетронутым, и будет использован метод суперкласса __hash__()
. То есть, если суперкласс является объектом, то он вернется к хешированию на основе идентификатора.frozen
: если равен True
(по умолчанию False), то при попытке изменить значения поля будет генерироваться исключение. Это имитирует frozen
экземпляры, доступные только для чтения. Если в классе определены методы __setattr__()
или __delattr__()
, то возникает ошибка TypeError
.
match_args
: Если значение True
(по умолчанию), то кортеж __match_args__
будет создан из списка аргументов сгенерированного метода __init__()
(даже если __init__()
не сгенерирован, см. Выше). Если значение False
или __match_args__
уже определен в классе, то __match_args__
сгенерировано не будет.
Новое в Python 3.10.
kw_only
: Если значение True
(по умолчанию), то все поля будут помечены как содержащие только ключевые слова. Если поле помечено как только ключевое слово, то единственное влияние состоит в том, что параметр __init__()
, созданный из поля, содержащего только ключевое слово, должен быть указан с ключевым словом при вызове __init__()
. Это не влияет ни на какие другие аспекты классов данных.
Дополнительно смотрите описание значения dataclasses.KW_ONLY
Новое в Python 3.10.
slots
: Если значение True
(по умолчанию False
), то атрибут __slots__
будет сгенерирован и вместо исходного класса будет возвращен новый класс. Если атрибут __slots__
уже определен в классе, то вызывается исключение TypeError
.
Новое в Python 3.10.
Изменено в Python 3.11: если имя поля уже включено в __slots__
базового класса, то оно не будет включено в сгенерированные __slots__
, чтобы предотвратить их переопределение. Поэтому не используйте __slots__
для получения имен полей класса данных. Вместо этого используйте dataclasses.fields()
. Чтобы иметь возможность определять унаследованные слоты, базовый класс __slots__
может быть любым итерируемым, но не итератором.
weakref_slot
: если True
(по умолчанию False
), добавляет слот с именем __weakref__
, который необходим для обеспечения возможности слабой ссылки экземпляра. Указание weakref_slot=True
, без указания также slots=True
является ошибкой.
Новое в Python 3.11.
Поля создаваемого типа могут дополнительно указывать значение по умолчанию, используя обычный синтаксис Python:
@dataclass class C: a: int # 'a' не имеет значения по умолчанию b: int = 0 # 'b' имеет значения по умолчанию 0
В этом примере и a
и b
будут включены в добавленный метод __init__()
, который будет определен как:
def __init__(self, a: int, b: int = 0):
Если поле без значения по умолчанию следует за полем со значением по умолчанию, то будет вызвано исключение TypeError
. Это верно либо когда это происходит в отдельном классе, либо в результате наследования классов.
Простое использование декоратора @dataclass
.
from dataclasses import dataclass @dataclass class Person: name: str age: int >>> p = Person('John Doe', 34) >>> p # Person(name='John Doe', age=34)
from dataclasses import dataclass @dataclass class Person: name: str = 'unknown' age: int = 0 >>> p = Person() >>> p # Person(name='unknown', age=0) >>> p1 = Person('John Doe', 34) >>> p1 # Person(name='John Doe', age=34)
repr
.При указании аргумента repr=False
, создаваемый тип не будет красиво выводится в терминале.
from dataclasses import dataclass @dataclass(repr=False) class Article(): title: str language: str >>> article = Article('DataClasses', 'Python3') >>> article # <__main__.Article object at 0x7f94b4605d60>
eq
.При указании аргумента eq=False
, два объекта сравниваются с использованием их хэша на основе их местоположения в памяти, как два обычных объекта. Поскольку два объекта имеют разное хеш-представление, их равенство возвращает False
.
@dataclass(eq=False) class Article(): title: str language: str # Создадим 2 одинаковых типа данных >>> article1 = Article('DataClasses', 'Python3') >>> article2 = Article('DataClasses', 'Python3') # сравним эти типы >>> article1 == article2 # False
order
.Сравнение двух классов данных не только ограничивается равенством, но также поддерживает операторы, >
, >=
, <
и <=
, когда в параметре аргумента задано значение order=True
.
Сравнение между объектами основано на сравнении соответствующих им атрибутов, которое выполняется по очереди, начиная с первого.
from dataclasses import dataclass @dataclass(order=True) class A(): var1: int var2: float >>> obj1 = A(1, 7.0) >>> obj2 = A(2, 7.0) >>> obj3 = A(1, 7.0) >>> obj4 = A(1, 8.0) >>> obj1 > obj2 # False >>> obj1 == obj3 # True >>> obj1 >= obj4 # False
frozen
.Аргумент frozen
устанавливает все переменные в классе данных как неизменяемые, которые после инициализации не могут быть переназначены на новое значение. Это похоже на поведение переменной Java, определенной при помощи оператора final
или оператора const
языка C.
from dataclasses import dataclass @dataclass(frozen=True) class A(): var1: int var2: float >>> obj1 = A(1, 7.0) >>> obj1.var1 = 10 # Traceback (most recent call last): # File "<stdin>", line 1, in <module> # File "<string>", line 4, in __setattr__ # dataclasses.FrozenInstanceError: cannot assign to field 'var1'