Количество полных объектов и подобъектов в Python

Я хотел бы сохранить количество объектов A и B, B подклассов от A. Таким образом, счет должен быть специфичным для A и B. Например, если я создаю 3 объекта A и 2 B объектов, в силу вызова конструктора, count для A становится 3+2=5, но я хотел бы сохранить как 3 (не когда используется как подобъект как часть B). Пожалуйста, прокомментируйте следующий фрагмент кода:

class A:
    acount = 0 # class variable
    def __init__(self, isFullA = True):
        if (isFullA):
            self.iamFullA = True
            A.acount += 1
        else:
            self.iamFullA = False
    def __del__(self):
        if (self.iamFullA):
            A.acount -= 1

class B(A):
    bcount = 0 # class variable
    def __init__(self, isFullB = True):
        A.__init__(self,False)
        if (isFullB):
            self.iamFullB = True
            B.bcount += 1
        else:
            self.iamFullB = False
    def __del__(self):
        if (self.iamFullB):
            B.bcount -= 1
#MAIN
L=[]
for i in range(3):
  L.append(A())
for i in range(2):
  L.append(B())
print "A.acount = " + str(A.acount)
print "B.bcount = " + str(B.bcount)

Выход:

A.acount = 3
B.bcount = 2

1 ответ

Решение

Вы делаете это сложным - все, что вам нужно, это иметь count Атрибут класса для каждого класса:

class A(object):
    _counter = 0

    @classmethod
    def _inc(cls):
        cls._counter += 1

    @classmethod
    def _dec(cls):
        cls._counter -= 1

    @classmethod
    def get_count(cls):
        return cls._counter

    def __init__(self):
        self._inc()

    def __del__(self):
        self._dec()


class B(A):
    _counter = 0

    def __init__(self, wot):
        super(B, self).__init__()
        self.wot = wot

L=[]
for i in range(3):
  L.append(A())
for i in range(2):
  L.append(B(i))
print "A.count = {}".format(A.get_count())
print "B.count = {}".format(B.get_count())

Обратите внимание, что я использовал classmethods чтобы убедиться, что мы обращаемся к атрибуту класса, как self._counter += 1 в __init__ создаст атрибут экземпляра. Вы также можете получить правильное поведение, используя type(self)._counter += 1 (или же self.__class__._counter += 1) но это немного уродливо имхо.

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

 class CounterType(type):
    def __new__(meta, name, bases, attribs):
        if "_counter" not in attribs:
            attribs["_counter"] = 0
        return type.__new__(meta, name, bases, attribs)

class CounterBase(object):
    __metaclass__ = CounterType
    @classmethod
    def _inc(cls):
        cls._counter += 1

    @classmethod
    def _dec(cls):
        cls._counter -= 1

    @classmethod
    def get_count(cls):
        return cls._counter

    def __init__(self):
        self._inc()

    def __del__(self):
        self._dec()


class A(CounterBase):
    pass


class B(A):
    def __init__(self, wot):
        super(B, self).__init__()
        self.wot = wot

L=[]
for i in range(3):
  L.append(A())
for i in range(2):
  L.append(B(i))
print "A.count = {}".format(A.get_count())
print "B.count = {}".format(B.get_count())
Другие вопросы по тегам