Простая примесь, которую можно добавить к любому классу, чтобы разрешить подсчет экземпляров

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

Зачем считать экземпляры?

Во-первых, зачем нам подсчитывать экземпляры объекта? Вот несколько примеров использования:

  • Мы хотим дать объектам уникальные идентификаторы во время выполнения.
  • Мы хотим отслеживать или подсчитывать создание экземпляров в целях отладки.
  • Количество экземпляров среды выполнения имеет некоторое значение для нашей программы (например, нам нужно отсортировать объекты по порядку создания).

Основной подход

Простой подход к подсчету экземпляров - просто добавить его прямо в свой класс:

class A:
    numInstances = 0
    def __init__(self):
        A.numInstances += 1
        self.count = A.numInstances

Это создает переменную класса с именем numInstances, которая отслеживает общее количество созданных экземпляров, и переменную экземпляра с именем count, которая содержит номер экземпляра для данного экземпляра.

So:

a = A()
b = A()
a.count            # returns 1
b.count            # returns 2
a.numInstances     # returns 2
b.numInstances     # returns 2

Делаем его многоразовым

Конечно, как хорошие программисты, мы хотим сделать эту функцию подсчета многоразовой. Затем несколько классов можно подсчитать независимо, унаследовав некоторый заранее созданный Countable класс.

Наш первый инстинкт - сделать что-то вроде этого:

class B : A
    pass # implement specialist functionality in B

Проблема в том, что B и A теперь используют одну и ту же переменную numInstances, предоставленную A, что дает нам:

b = B()
b.count    # returns 3, not 1 as expected

Однако есть способ решить эту проблему с помощью метаклассов Python. Это позволяет нам создать отдельное количество экземпляров для каждого подкласса:

Класс Countable теперь можно использовать как миксин:

class A(Countable):
    pass
class B (Countable):
    pass
a = A()
b = B()
a.count    # prints 1
b.count    # also prints 1. numInstances is no longer shared

Спасибо за прочтение. Если вы нашли это полезным, ознакомьтесь с другими моими статьями на Medium: