#python #python-dataclasses
#питон #python-классы данных
Вопрос:
У меня есть следующий класс данных.
@dataclass(frozen=True)
class myDataClass:
x: float
y: float
Я хочу, чтобы каждый раз, когда я создаю объект этого класса, он помечался уникальным идентификатором, который увеличивается с 0.
Итак, в первый раз я говорю first = myDataClass(0, 1)
, что тогда я должен был first.id == 0
, а потом, если я говорю second = myDataClass(0, 1)
, я должен получить second.id == 1
.
Ответ №1:
Потокобезопасный уникальный идентификатор может быть сгенерирован с помощью itertools.count()
метода экземпляра __next__
в качестве default_factory
для поля:
from dataclasses import dataclass, field
from itertools import count
@dataclass(frozen=True)
class myDataClass:
x: float
y: float
id: int = field(default_factory=count().__next__, init=False)
Это быстрее, чем другие варианты, не требует пользовательского кода и, по крайней мере, в ссылочном интерпретаторе CPython, потокобезопасно ( itertools.count
реализовано на C и не освобождает GIL, поэтому нет шансов, что два экземпляра получат одинаковое id
значение ).
Комментарии:
1. о-о-о, это действительно здорово.
Ответ №2:
Это немного сложно для замороженных классов данных, потому что любой код, который вы пишете, который динамически обновляет поле, сталкивается с FrozenInstanceError
, но это, безусловно, возможно:
from dataclasses import dataclass, field
@dataclass(frozen=True)
class myDataClass:
x: float
y: float
id: int = field(init=False)
def __post_init__(self):
if not hasattr(myDataClass, "_COUNT"):
myDataClass._COUNT = 0
object.__setattr__(self, "id", myDataClass._COUNT)
myDataClass._COUNT = 1
Что должно работать так, как вы ожидали:
>>> (myDataClass(1.0,2.0))
myDataClass(x=1.0, y=2.0, id=0)
>>> (myDataClass(1.0,2.0))
myDataClass(x=1.0, y=2.0, id=1)
>>> (myDataClass(1.0,2.0))
myDataClass(x=1.0, y=2.0, id=2)
>>> (myDataClass(1.0,2.0))
myDataClass(x=1.0, y=2.0, id=3)
Ответ №3:
Вы можете использовать default_factory
для атрибутов классов данных, которые функционируют так, как вы хотите, и использовать переменную класса для отслеживания максимального используемого идентификатора.
from dataclasses import dataclass, field
from typing import ClassVar
def _assign_id():
new_id = myDataClass._next_id
myDataClass._next_id = 1
return new_id
@dataclass(frozen=True)
class myDataClass:
x: float
y: float
id: int = field(default_factory=_assign_id, init=False)
_next_id: ClassVar[int] = 0