I have a set of plugins that inherit from a metaclass. the metaclasss is defined like so:
from abc import ABC, abstractmethod
class MetaReader(ABC):
def __init__(self, arg1, arg2, **kwargs):
...
and the subclass like so:
from utils.MetaReader import MetaReader
class ABF2Reader(MetaReader):
...
This works, as far as I can tell, and I can instantiate classes and use them as intended. However, at some points I need to load these classes as plugins without instantiating them, and when I do, I need to check their subclass against the proper metaclass to know what to do with them when loaded. And there, I get some weird results:
from utils.MetaReader import MetaReader
from plugins.datareaders.ABF2Reader import ABF2Reader
print(type(reader)) #reader is an instance of ABF2Reader
print(type(MetaReader)) #MetaReader is just the metaclass, not instantiated
print(type(ABF2Reader)) #Just the subclass, not instantiated
prints:
<class 'plugins.datareaders.ABF2Reader.ABF2Reader'>
<class 'abc.ABCMeta'>
<class 'abc.ABCMeta'>
The type for reader
is what I expect: it's an instance of ABF2Reader. But the types for the other two are not. type(MetaReader)
is also fine, but I expect type(ABF2Reader)
to give me <class 'MetaReader'>
, not <class 'abc.ABCMeta'>
Clearly I am using metaclasses wrong. Can someone shed some light on where I am screwing this up?
This code is not defining any new metaclasses to startwith. And the truth is that you probably don´t need custom metaclasses anyway - it would be possible to tell if you said what is your intention with the use of metaclasses. As it is, though, we just have a 2-class hierarchy that does nothing.
So, abc.ABC
, from which you inherit is a class, not a metaclass, which makes its subclasses work with the abc.abstractmethod
decorator, and allow other, unrelated classes, to be registered as virtual subclasses of themselves with the myclass.register
method.
What happens is that abc.ABC
itself uses a custom metaclass, the abc.ABCMeta
class - and you don´t show any reason why you would want to customize it. Anyway, that is why type(MetaReader)
outputs ABCMeta: its metaclass, which means, the class from which the class "MetaReader" is itself an instance, is abc.ABCMeta
, through inheritance of abc.ABC
.
To apply a custom metaclass to your own classes, you´d first have to create such a metaclass, by inheriting it from type
, or, in this case, from abc.ABCMeta
(which inherits from type
). Then, upon declaring a class, the named argument metaclass=MyMetaClass
have to be used, along with the class bases:
class MetaReader(abc.ABCMeta):
# body which actually makes something useful on class
# creation time, or the class behavior itself,
# and which can´t be done by __init_subclass__
# (usually by overriding __new__ or __call__ ) ...
class ABF2Reader(abc.ABC, metaclass=MetaReader):
...
Comlementing: after interacting with the O.P. in the comments - what they need is a way to find the superclass of the classes, not the metaclasses. The most usual way of checking that is with the issubclass
call - metaclasses are not involved as described above. Onee may also want to inspect the class' __bases__
and __mro__
attributes at runtime.