python: определение реестра в базовом классе - PullRequest
0 голосов
/ 01 сентября 2010

Я реализую перечисление, используя базовый класс, который определяет множество методов. Фактические перечисления являются подклассами этого, без дополнительных методов или атрибутов. (Каждый подкласс заполняется своими собственными значениями с использованием конструктора, определенного в базовом классе).

Я использую реестр (атрибут класса, в котором хранятся все экземпляры этого класса). В идеале я бы хотел избежать определения его в каждом подклассе. К сожалению, если я определю его в базовом классе, все подклассы будут иметь общий реестр.

Какой хороший подход здесь?

Ниже приведена реализация, если она помогает (она основана на комментарии @jchl в классе перечисления python для целей ORM ).

class IterRegistry(type):
    def __iter__(cls):
        return iter(cls._registry.values())

class EnumType(metaclass = IterRegistry):
    _registry = {}
    _frozen = False
    def __init__(self, token):
        if hasattr(self, 'token'):
            return
        self.token = token
        self.id = len(type(self)._registry)
        type(self)._registry[token] = self

    def __new__(cls, token):
        if token in cls._registry:
            return cls._registry[token]
        else:
            if cls._frozen:
                raise TypeError('No more instances allowed')
            else:
                return object.__new__(cls)

    @classmethod
    def freeze(cls):
        cls._frozen = True

    def __repr__(self):
        return self.token

    @classmethod
    def instance(cls, token):
        return cls._registry[token]

class Enum1(EnumType): pass
Enum1('a')
Enum1('b')
for i in Enum1:
  print(i)

# not going to work properly because _registry is shared
class Enum2(EnumType): pass

Ответы [ 3 ]

3 голосов
/ 01 сентября 2010

Поскольку у вас уже есть метакласс, вы также можете использовать его для автоматического добавления отдельного атрибута _registry в каждый подкласс.

class IterRegistry(type):
    def __new__(cls, name, bases, attr):
        attr['_registry'] = {} # now every class has it's own _registry
        return type.__new__(cls, name, bases, attr)
1 голос
/ 01 сентября 2010

У Марти Алчина есть очень хороший пример: см. его запись в блоге .

0 голосов
/ 01 сентября 2010

Что делать, если вы используете один и тот же реестр, но с подрегистрами для каждого класса, то есть

if cls.__name__ not in self._registry:
    self._registry[cls.__name__] = {}
self._registry[cls.__name__][token] = cls

На самом деле вам даже не нужно cls.__name__, вы сможете использовать clsв качестве ключа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...