Reputation: 7361
How can I check if a class is child of a parent created by a factory class?
Consider the following trivial example:
from itertools import count
def basefactory():
class Base:
_idc = count(0)
def __init__(self):
self._id = next(self._idc)
return Base
Then I create children using the factory class:
class A(basefactory()):
def __init__(self):
super().__init__()
class B(basefactory()):
def __init__(self):
super().__init__()
How can I test if A
or B
are children of a class created by the factory class?
Without the factory class I would use: issubclass(A, Base))
but of course this doesn't work with the factory class, since Base
is not defined in the global space.
The reason of this setup is that I want A
and B
to have a different _idc
counters to generate consecutive _id
s for each instance of the child classes.
If A
and B
inherits directly from Base
the counter is shared. Let me illustrate with an example what I mean.
With the factory class setup described above, if I do:
ll = [A(), A(), B(), B()]
for e in ll:
print(e._id, end=", ")
it prints: 0, 1, 0, 1,
. If instead I move Base
in the global space and A
and B
inherit directly from Base
, the previous code prints: 0, 1, 2, 3,
.
I want the _id
to be 0, 1, 0, 1,
, this is the reason I'm using the factory class setup.
In my real case I don't have just A
and B
(I have 10 classes created by the factory class and they could increase in future), so I don't want to repeat myself and initialize the counters in each child.
However I also need to assert if a class is child of Base
, or in other terms, if it is created through the factory class. And this is the question. Is it possible to do by checking the class hierarchy with issubclass
? Or I need to change the setup or use a workaround like people suggested in the comments?
I don't think is a duplicate of Understanding Python super() with __init__
() methods. I know what super
does, and is not useful in this specific case. I want each child class to have a different counter, I don't see how referring to the parent class is helpful.
Maybe it is helpful (if so, please post an answer), but since the proposed duplicate doesn't deal with factory classes, I think this question is still different.
Upvotes: 2
Views: 1792
Reputation: 532538
I think a decorator would do what you want (add an instance counter to a class) more simply than a factory function that generates an otherwise unnecessary base class.
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=", ")
Upvotes: 2
Reputation: 1864
Well, I don't know how to access this information properly, but when typing help(A)
, you get 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)
I get it must be possible to access it properly
Upvotes: 0