Наследование классов фабрики Python - PullRequest
0 голосов
/ 30 мая 2019

Как я могу проверить, является ли класс дочерним по отношению к родительскому объекту, созданному классом фабрики?

Рассмотрим следующий тривиальный пример:

from itertools import count
def basefactory():
    class Base:
        _idc = count(0)
        def __init__(self):
            self._id = next(self._idc)
    return Base

Затем я создаю потомков, используя фабричный класс:

class A(basefactory()):
    def __init__(self):
        super().__init__()

class B(basefactory()):
    def __init__(self):
        super().__init__()

Как проверить, являются ли A или B дочерними элементами класса, созданного фабричным классом?
Без фабричного класса я бы использовал: issubclass(A, Base)) но, конечно,это не работает с фабричным классом, так как Base не определен в глобальном пространстве.

Причина этой настройки в том, что я хочу, чтобы A и B имели разные _idc счетчики для генерации последовательных _id с для каждого экземпляра дочерних классов.
Если A и B наследуются непосредственно от Base, то счетчик используется совместно.Позвольте мне проиллюстрировать на примере, что я имею в виду.

При заводской настройке класса, описанной выше, если я сделаю:

ll = [A(), A(), B(), B()]   
for e in ll:
    print(e._id, end=", ")

, она напечатает: 0, 1, 0, 1,.Если вместо этого я переместлю Base в глобальное пространство, а A и B наследуют непосредственно от Base, предыдущий код напечатает: 0, 1, 2, 3,.

Я хочу, чтобы _id было 0, 1, 0, 1,, по этой причине я использую заводскую настройку класса.В моем реальном случае у меня нет только A и B (у меня есть 10 классов, созданных фабричным классом, и они могут увеличиться в будущем), поэтому я не хочу повторяться и инициализировать счетчики в каждомребенок.

Однако мне также необходимо подтвердить, является ли класс дочерним по отношению к Base, или, другими словами, если он создан с помощью фабричного класса.И это вопрос.Можно ли это сделать, проверив иерархию классов с помощью issubclass?Или мне нужно изменить настройку или использовать обходной путь, как предложили люди в комментариях?

О предлагаемом дубликате

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

Ответы [ 2 ]

1 голос
/ 06 июля 2019

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

from itertools import count

def add_counter(cls):
    cls._idc = count(0)
    old_init = cls.__init__
    def __init__(self, *args, **kwargs):
        old_init(self, *args, **kwargs)
        self._id  = next(self._idc)
    cls.__init__ = __init__
    return cls

@add_counter
class A:
    pass

@add_counter
class B:
    pass

ll = [A(), A(), B(), B()]
for e in ll:
    print(e._id, end=", ")
0 голосов
/ 30 июня 2019

Ну, я не знаю, как правильно получить доступ к этой информации, но при наборе help(A) вы получаете Base:

Help on class A in module __main__:
class A(Base)
 |  Method resolution order:
 |      A
 |      Base
 |      builtins.object
 |  
 |  Methods inherited from Base:
 |  
 |  __init__(self)
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from Base:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)

Я понимаю, что должен быть возможный доступ к нему должным образом

...