Как получить индекс экземпляра класса данных Python3? - PullRequest
6 голосов
/ 07 ноября 2019

Я хотел бы ограничить максимальное количество экземпляров класса данных и узнать индекс экземпляра. Это поведение, которое я хочу:

Veget('tomato', 2.4, 5)
Veget('salad', 3.5, 2)
Veget('carot', 1.2, 7)

for Veget in Veget.instances:
    print(Veget)
Veget(index=0, name='tomato', price=2.4, quantity=5)
Veget(index=1, name='salad', price=3.5, quantity=2)
Veget(index=2, name='carot', price=1.2, quantity=7)

Я попробовал следующее, которое обрабатывает предел создания:

from dataclasses import dataclass

MAX_COUNT = 3


class Limited:

    instances = []

    def __new__(cls, *_):
        if len(cls.instances) < MAX_COUNT:
            newobj = super().__new__(cls)
            cls.instances.append(newobj)
            return newobj
        else:
            raise RuntimeError('Too many instances')

@dataclass
class Veget(Limited):
    name: str
    price: float
    quantity: int

Но индекс не будет отображаться, когданапечатано:

Veget(name='tomato', price=2.4, quantity=5)
Veget(name='salad', price=3.5, quantity=2)
Veget(name='carot', price=1.2, quantity=7)

1 Ответ

2 голосов
/ 08 ноября 2019

Наложение неявных ограничений на классы данных или требование какой-либо проверки обычно осуществляется через назначенный __post_init__ вместо использования наследования объектов. Реализация, использующая это, может выглядеть так, что, на мой взгляд, будет немного легче поддерживать и понимать:

from dataclasses import dataclass, field

MAX_COUNT = 3
VEGET_INDEX = []


@dataclass
class Veget:
    index: int = field(init=False)
    name: str
    price: float
    quantity: int

    def __post_init__(self):
        self.index = len(VEGET_INDEX)
        if self.index >= MAX_COUNT:
            raise RuntimeError("Too many instances")
        VEGET_INDEX.append(self)

Вы также можете использовать счетчик вместо списка, который увеличивается в подпрограмме post init, но список ссылок кажется удобным для целей отладки. В любом случае, создание трех разрешенных экземпляров и попытка создать четвертый будет выглядеть так:

>>> Veget('tomato', 2.4, 5)
Veget(index=0, name='tomato', price=2.4, quantity=5)
>>> Veget('salad', 3.5, 2)
Veget(index=1, name='salad', price=3.5, quantity=2)
>>> Veget('carot', 1.2, 7)
Veget(index=2, name='carot', price=1.2, quantity=7)
>>> Veget('potato', 0.7, 3)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<string>", line 5, in __init__
  File "<input>", line 17, in __post_init__
RuntimeError: Too many instances
...