Как проверить поля data class на null и в зависимости от результата присвоить значения полей в переменную?
Данные в класс поступают из сервиса, поля необязательные для заполнения. Стоит задача проверить все поля на null и в случае, если поле не пустое и не является null присвоить его в переменную:
var accost = "друг"
Переменная в дальнейшем будет использоваться для приветствия пользователя. На данный момент реализация следующая:
if(!LoginResponse.accost.isNullOrEmpty()) accost = LoginResponse.data.accost else if (!LoginResponse.name.isNullOrEmpty()) accost = LoginResponse.data.name else if(!LoginResponse.fullname.isNullOrEmpty()) accost = LoginResponse.data.fullname Toast.makeText("$accost", Toast.LENGTH_LONG).show()
Полей в data class на самом деле достаточно много, хочется получить более красивый и читаемый код. В Kotlin имеется замечательный оператор when(условие) возможно ли его как то применить к данной ситуации?
Декоратор dataclass() модуля dataclasses в Python
Создание класса для хранения пользовательских данных
Синтаксис:
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__() . То есть, если суперкласс является объектом, то он вернется к хешированию на основе идентификатора.
Поля создаваемого типа могут дополнительно указывать значение по умолчанию, используя обычный синтаксис 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 #
Использование аргумента 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 .
Сравнение двух классов данных не только ограничивается равенством, но также поддерживает операторы, > , >= , < и
Сравнение между объектами основано на сравнении соответствующих им атрибутов, которое выполняется по очереди, начиная с первого.
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 "", line 1, in # File "", line 4, in __setattr__ # dataclasses.FrozenInstanceError: cannot assign to field 'var1'
- КРАТКИЙ ОБЗОР МАТЕРИАЛА.
- Декоратор dataclass() модуля dataclasses
- Функция field() модуля dataclasses
- Функция asdict() модуля dataclasses
- Функция astuple() модуля dataclasses
- Функция make_dataclass() модуля dataclasses
- Функция replace() модуля dataclasses
- Функция is_dataclass() модуля dataclasses
- Функция fields() модуля dataclasses
- Значение KW_ONLY модуля dataclasses
Введение в Python Data Classes (часть 2)
Я Сергей Балакирев и мы продолжаем тему Data Classes – классы данных. На предыдущем занятии мы в целом научились объявлять такие классы с помощью декоратора dataclass и определять набор необходимых атрибутов:
@dataclass class ThingData: name: str weight: int price: float = 0 dims: list = field(default_factory=list)
Но давайте представим, что нам нужно в некотором классе, например, Vector3D при инициализации формировать вычисляемое свойство:
class Vector3D: def __init__(self, x: int, y: int, z: int): self.x = x self.y = y self.z = z self.length = (x * x + y * y + z * z) ** 0.5
Здесь локальный атрибут length вычисляется на основе параметров x, y, z. Как это можно сделать при объявлении Data Classes?
Метод __post_init__()
Вначале, очевидно, нужно прописать класс с тремя атрибутами следующим образом:
@dataclass class V3D: x: int y: int z: int
Что делать дальше, как определить локальный атрибут length внутри объекта класса V3D? Для этого существует следующая хитрость. Инициализаторы классов, сформированные с помощью декоратора dataclass, в конце своего вызова вызывают специальный метод __post_init__(). Именно в этом методе можно формировать любые вычисляемые свойства, например, так:
@dataclass class V3D: x: int y: int z: int def __post_init__(self): self.length = (self.x * self.x + self.y * self.y + self.z * self.z) ** 0.5
Если далее мы сформируем объект этого класса и выведем его в консоль:
v = V3D(1, 2, 3) print(v)
Спрашивается, почему здесь не видно свойства length? В действительности, оно присутствует в объекте v и мы в этом легко можем убедиться:
print(v.__dict__)
Но тогда почему оно не выводится функцией repr()? Дело в том, что магический метод __repr__() выводит только те атрибуты, которые были указаны при объявлении класса. Все остальные, что создаются в процессе формирования объекта, не учитываются в методе __repr__(). Как тогда выйти из этой ситуации и указать, что локальный атрибут length также следует отображать? Очень просто! Давайте укажем этот атрибут при объявлении класса с небольшим уточнением:
@dataclass class V3D: x: int y: int z: int length: float = field(init=False) def __post_init__(self): self.length = (self.x * self.x + self.y * self.y + self.z * self.z) ** 0.5
Мы здесь воспользовались уже знакомой нам функцией field() и отметили, что атрибут length не следует использовать в качестве параметра инициализатора. Изящно, правда?! Теперь, при отображении объекта v класса, мы увидим и параметр length.
Функция field()
- repr – булевое значение True/False указывает использовать ли атрибут в магическом методе __repr__() (по умолчанию True);
- compare – булевое значение True/False указывает использовать ли атрибут при сравнении объектов (по умолчанию True);
- default – значение по умолчанию (начальное значение).
@dataclass class V3D: x: int = field(repr=False) y: int z: int = field(compare=False) length: float = field(init=False, compare=False) def __post_init__(self): self.length = (self.x * self.x + self.y * self.y + self.z * self.z) ** 0.5
Тогда при отображении и сравнении двух объектов:
v = V3D(1, 2, 3) v2 = V3D(1, 2, 5) print(v) print(v == v2)
мы увидим только три атрибута: y, z, length и результат True, т.к. координаты x, y объектов v и v2 совпадают. С остальными параметрами функции field() можно познакомиться на странице официальной документации: https://docs.python.org/3/library/dataclasses.html
Объявление параметров типа InitVar
Давайте теперь предположим, что мы бы хотели вычислять длину вектора в зависимости от значения некоторого параметра, например, calc_len. При описании обычного инициализатора это можно было бы сделать следующим образом:
class Vector3D: def __init__(self, x: int, y: int, z: int, calc_len: bool = True): self.x = x self.y = y self.z = z self.length = (x * x + y * y + z * z) ** 0.5 if calc_len else 0
А как это сделать при объявлении Data Classes? Для определения параметров, участвующих в инициализации (таких, как calc_len) в модуле dataclasses есть специальный класс типа InitVar:
from dataclasses import dataclass, field, InitVar
Если при объявлении атрибут аннотируется этим классом, то он автоматически передается как параметр в метод __post_init__(), чтобы им можно было воспользоваться при формировании вычисляемых свойств:
@dataclass class V3D: x: int = field(repr=False) y: int z: int = field(compare=False) calc_len: InitVar[bool] = True length: float = field(init=False, compare=False, default=0) def __post_init__(self, calc_len: bool): if calc_len: self.length = (self.x * self.x + self.y * self.y + self.z * self.z) ** 0.5
Обратите внимание, я здесь для атрибута length добавил параметр default=0 в функции field(). То есть, начальное значение атрибута length равно нулю. Если параметр calc_len равен True, то в методе __post_init__() будет пересчитано и сформировано новое значение локального атрибута length.
Параметры декоратора dataclass
До сих пор мы с вами использовали декоратор dataclass с параметрами по умолчанию. Однако ему можно передавать различные аргументы и управлять процессом формирования итогового класса. Вот основные параметры, которые принимает декоратор dataclass.
Параметр Описание init = [True | False] Принимает булево значение, по умолчанию True. Если значение True, то в классе объявляется инициализатор, иначе – не объявляется. repr = [True | False] Принимает булево значение, по умолчанию True. Если значение True, то в классе объявляется магический метод __repr__(), иначе – не объявляется. eq = [True | False] Принимает булево значение, по умолчанию True. Если значение True, то в классе объявляется магический метод __eq__(), иначе – не объявляется. order = [True | False] Принимает булево значение, по умолчанию False. Если значение True, то в классе объявляются магические методы для операций сравнения ; >=, иначе – не объявляются. unsafe_hash = [True | False] Влияет на формирование магического метода __hash__() frozen = [True | False] Принимает булево значение, по умолчанию False. Если значение True, то атрибуты объектов класса становятся неизменными (можно только проинициализировать один раз в инициализаторе). slots = [True | False] Принимает булево значение, по умолчанию False. Если значение True, то атрибуты объявляются в коллекции __slots__. Существуют и другие параметры декоратора dataclass. Подробно о них можно почитать на странице официальной документации: https://docs.python.org/3/library/dataclasses.html Давайте последовательно рассмотрим основные из них. Первые параметры init, repr, eq я, думаю, понятны. Если в декоратор передать аргумент init=False:
@dataclass(init=False)
то класс будет сформирован без собственного инициализатора (будет использован инициализатор базового класса). В результате у нас не получится создать объект с передачей значений аргументов:
v = V3D(1, 2, 3, False)
Это бывает полезно, когда все описанные атрибуты принимают значения по умолчанию и не предполагается их сразу переопределять в инициализаторе. Например, если класс в дальнейшем будет использован как базовый для построения других дочерних классов. Следующий параметр:
@dataclass(repr=False)
запрещает формирование магического метода __repr__() внутри текущего класса. В результате, будет использован аналогичный метод базового класса. В этом легко убедиться, если создать объект и вывести его в консоль:
v = V3D(1, 2, 3, False) print(v)
Увидим что то похожее на: <__main__.V3D object at 0x00000236FAD67D50>По аналогии работает параметр eq:
@dataclass(repr=False, eq=False)
Он запрещает формирование собственного магического метода __eq__() для сравнения объектов между собой на равенство. Теперь объекты сравниваются по их идентификаторам, и так как они разные, то при сравнении:
v = V3D(1, 2, 3, False) v2 = V3D(1, 2, 3) print(v == v2)
получаем значение False. Следующий параметр order может быть установлен в True только совместно с eq=True. Например, следующая строчка приведет к ошибке:
@dataclass(eq=False, order=True)
Поэтому нам нужно или убрать параметр eq (по умолчанию он True), либо явно прописать у него значение True:
@dataclass(eq=True, order=True)
Я, думаю, вы догадались почему? Операции сравнения на больше или равно, меньше или равно используют магический метод __eq__(). Поэтому он должен присутствовать. Итак, после включения параметра order, у нас появляется возможность сравнивать объекты класса на больше, меньше и больше или равно и меньше или равно:
@dataclass(eq=True, order=True) class V3D: x: int y: int z: int v = V3D(1, 2, 5) v2 = V3D(1, 2, 3) print(v v2) # False print(v > v2) # True
Сравнение выполняется на уровне кортежей, содержащих значения атрибутов (x, y, z) в порядке их объявления в классе. В данном случае происходит последовательное сравнение сначала значений x между собой, затем, y и потом – z. Как только встречается пара, для которой можно вычислить значение True или False, проверка завершается. Фактически, в приведенном примере, сравниваются между собой только последние числа 5 и 3, остальные равны, поэтому операции < и >их пропускают. Если нам нужно исключить какие-либо атрибуты из операций сравнений, то, как я уже отмечал, для этого следует использовать функцию field() и в ней через параметр compare исключить соответствующее поле:
@dataclass(eq=True, order=True) class V3D: x: int = field(compare=False) y: int z: int
Теперь сравниваться будут объекты только по двум локальным атрибутам y и z. Здесь следует обратить внимание на то, что если в классе объявить какой-либо метод сравнения на больше, меньше или больше либо равно или меньше либо равно, то возникнет исключение TypeError:
@dataclass(order=True) class V3D: x: int = field(compare=False) y: int z: int def __lt__(self, other): return self.x other.x and self.y other.y
Последний параметр, который мы рассмотрим – frozen, позволяет «замораживать» значения атрибутов класса. Например:
@dataclass(frozen=True) class V3D: x: int y: int z: int v = V3D(1, 2, 3) print(v) v.x = 5
DataClass в Python
Конструкции dataclass доступны в Python 3.7 и старше. Их можно использовать как контейнеры данных и не только. Конструкции dataclass позволяют писать шаблонный код и упрощают процесс создания классов, ведь в них для этого есть специальные методы.
Первый Dataclass
Создадим DataClass, представляющий собой точку в трехмерной системе координат.
Декоратор @dataclass используется для создания Data Class. x , y и z являются его полями. Стоит отметить, что с ними необходимо использовать определения типов данных. При этом они не являются объявлениями статического типа, и кто угодно может передать данные любого типа кроме int полям x , y или z .
from dataclasses import dataclass @dataclass class Coordinate: x: int y: int z: intПо умолчанию у Data Class есть методы __init__ , __repr__ и __eq__ , поэтому их не нужно реализовывать самостоятельно.
И пусть __init__ , __repr__ и __eq__ не реализованы в классе Coordinate их по-прежнему можно использовать благодаря dataclass . Это здорово экономит время.
from dataclasses import dataclass @dataclass class Coordinate: x: int y: int z: int a = Coordinate(4, 5, 3) print(a) # результат: Coordinate(x=4, y=5, z=3)Значения по умолчанию для полей
Полям можно присваивать значения по умолчанию. Используем пример. Как видно по полю pi , можно запросто присвоить значение по умолчанию для полей в DataClass.
from dataclasses import dataclass @dataclass class CircleArea: r: int pi: float = 3.14 @property def area(self): return self.pi * (self.r ** 2) a = CircleArea(2) print(repr(a)) # вернется: CircleArea(r=2, pi=3.14) print(a.area) # вернется: 12.56Изменение полей и DataClass
Изменять поля и DataClass можно за счет параметров декоратора или функции поля. Все случаи будут рассмотрены в примерах.
Data Class: изменяемые или нет?
По умолчанию dataclass изменяемые, что значит, что полям можно присваивать значения. Но их же можно сделать и неизменяемыми, задав значение True для параметра frozen .
Изменяемый пример
from dataclasses import dataclass @dataclass class CircleArea: r: int pi: float = 3.14 @property def area(self): return self.pi * (self.r ** 2) a = CircleArea(2) a.r = 5 print(repr(a)) # вернется: CircleArea(r=5, pi=3.14) print(a.area) # вернется: 78.5Неизменяемый пример
Когда значение frozen равно True , присваивать значения полям больше нельзя. Дальше показано соответствующее исключение.
from dataclasses import dataclass @dataclass(frozen=True) class CircleArea: r: int pi: float = 3.14 @property def area(self): return self.pi * (self.r ** 2) a = CircleArea(2) a.r = 5 # Вернется исключение: dataclasses.FrozenInstanceError: # cannot assign to field 'r'Сравнение Data Classes
Представьте, что вы хотите создать DataClass, представляющий Vector и сравнить их. Как это сделать? Для сравнения нужны методы __lt__ или __gt__ .
По умолчанию значение параметра order в Data Class равняется False . Если поменять его на True , то методы __lt__ , __le__ , __gt__ и __ge__ для Data Class будут сгенерированы автоматически. Таким образом можно сравнить объекты так, будто бы они являются кортежами полей.
Разберем на примере. Задав order значение True , можно сравнить v2 и v1 . Но есть проблема логики сравнения. Если сравнить, например, v2 > v1 , то векторы будут сравниваться вот так: (8, 15) > (7, 20) . Таким образом значением операции будет True .
Стоит напомнить, что сравнение кортежей происходит по порядку. Сначала сравниваются 8 и 7, и если результат равен True , то результатом всего сравнения будет True . Если бы они были равны, то произошло бы сравнение 15 > 20 и результат стал бы False .
from dataclasses import dataclass, field @dataclass(order=True) class Vector: x: int y: int v1 = Vector(8, 15) v2 = Vector(7, 20) print(v2 > v1)Очевидно, что в таком сравнении нет никакого смысла. Правильнее было бы сравнивать величину векторов. Проблема в том, что не хотелось бы высчитывать эту величину самостоятельно при создании экземпляров.
В этом случае можно воспользоваться функцией field и методом __post_init__ . Функция field позволит настроить поле magnitude , а __post_init__ — определить величину вектора после инициализации.
Поле magnitude было изменено с помощью функции field из Data Class. Задавая значение False для init , мы утверждаем, что не хотим иметь параметр magnitude в методе __init__ . Потому что его значение можно задать с помощью метода __post_init__ после инициализации.
Конвертация в словарь или кортеж
Можно получить атрибуты Data Class в кортеже или словаре. Для этого нужно лишь импортировать функции asdict и astuple из Data Class.
from dataclasses import dataclass, asdict, astuple @dataclass class Vector: x: int y: int z: int v = Vector(4, 5, 7) print(asdict(v)) # Вернется : print(astuple(v)) # Вернется : (4, 5, 7)Наследование
Можно создавать подклассы для Data Class как для обычных классов в Python.
from dataclasses import dataclass @dataclass class Employee: name: str lang: str @dataclass class Developer(Employee): salary: int Alex = Developer('Alex', 'Python', 5000) print(Alex) # Вернется: Developer(name='Alex', lang='Python', salary=5000)Но есть распространенная ошибка при использовании наследования. Когда значением поля lang по умолчанию является Python, нужно задавать значения по умолчанию для полей следом за lang .
from dataclasses import dataclass @dataclass class Employee: name: str lang: str = 'Python' @dataclass class Developer(Employee): salary: int Alex = Developer('Alex', 'Python', 5000) # Вернется: TypeError: non-default argument 'salary' follows default argumentЧтобы понять, зачем это нужно, рассмотрим, как выглядит метод __init__ . Вспомним, что параметры со значением по молчанию всегда идут после параметров без них.
def __init__(name: str, lang: str = 'Python', salary: int): ...Исправим, задав значение по умолчанию для поля salary .
from dataclasses import dataclass @dataclass class Employee: name: str lang: str = 'Python' @dataclass class Developer(Employee): salary: int = 0 Alex = Developer('Alex', 'Python', 5000) print(Alex) # Вернется: Developer(name='Alex', lang='Python', salary=5000)Преимущества слотов
По умолчанию атрибуты хранятся в словаре. Можно получить преимущество от слотов для более быстрого доступа к атрибутам и использовать меньше памяти. Однако в подробностях эта тема здесь рассматриваться не будет.
from dataclasses import dataclass @dataclass class Employee: name: str lang: str Alex = Employee('Alex', 'Python') print(Alex.__dict__) #Слоты нужны для использования меньшего количества памяти и более быстрого доступа к атрибутам.
from dataclasses import dataclass @dataclass class Employee: __slots__ = ('name', 'lang') name: str lang: str Alex = Employee('Alex', 'Python')Параметры Dataclass
Некоторые параметры в декораторе Data Class были изменены для настройки Data Class. Вот они:
- init : метод __init__ будет сгенерирован в Data Class при значении True . ( True – значение по умолчанию)
- repr : метод __repr__ будет сгенерирован в Data Class при значении True . ( True – значение по умолчанию)
- eq : метод __eq__ будет сгенерирован в Data Class при значении True . ( True – значение по умолчанию)
- order : методы __lt__ , __le__ , __gt__ и __ge__ будут сгенерированы в Data Class при значении True . ( False – значение по умолчанию)
- unsafe_hash : метод __hash__ будет сгенерирован в Data Class при значении True . ( False – значение по умолчанию)
- frozen : если True , то значения полям присваивать нельзя ( False – значение по умолчанию).
Примечание: eq должно быть равно True , если значение order равняется True , иначе будет исключение ValueError .
Параметры полей
- init : это поле включено в сгенерированный метод __init__ при значении True ( True – значение по умолчанию)
- repr : это поле включено в сгенерированный метод __init__ при значении True ( True – значение по умолчанию)
- compare : это поле включено в методы общего сравнения и равенства при значении True ( True – значение по умолчанию)
- hash : это поле включено в сгенерированный метод __hash__ при значении True ( None – значение по умолчанию)
- default : это будет значение по умолчанию для поля (если указано)
- default_factory : если указано, должно быть вызываемым объектом без аргументов, который вызывается, когда для поля требуется значение по умолчанию
- metadata : это может быть мапинг или None – пустой словарь.