I have an esoteric question involving Python metaclasses. I am creating a Python package for web-server-side code that will make it easy to access arbitrary Python classes via client-side proxies. My proxy-generating code needs a catalog of all of the Python classes that I want to include in my API. To create this catalog, I am using the __metaclass__
special attribute to put a hook into the class-creation process. Specifically, all of the classes in the "published" API will subclass a particular base class, PythonDirectPublic
, which itself has a __metaclass__
that has been set up to record information about the class creation.
So far so good. Where it gets complicated is that I want my PythonDirectPublic
itself to inherit from a third-party class (enthought.traits.api.HasTraits
). This third-party class also uses a __metaclass__
.
So what's the right way of managing two metaclasses? Should my metaclass be a subclass of Enthought's metaclass? Or should I just invoke Enthought's metaclass inside my metaclass's __new__
method to get the type object that I will return? Or is there some other mystical incantation to use in this particular circumstance?
Specifically, all of the classes in the "published" API will subclass a particular base class, PythonDirectPublic
Rather than adding another metaclass, you could recursively use the result of PythonDirectPublic.subclasses().
Should my metaclass be a subclass of Enthought's metaclass?
I believe that is in fact your only choice. If the metaclass of a derived class is not a subclass of the metaclasses of all of its bases then Python will throw a TypeError when you try to create the derived class. So your metaclass for PythonDirectPublic
should look something like
class DerivedMetaClass(BaseMetaClass):
def __new__(cls, name, bases, dct):
# Do your custom memory allocation here, if any
# Now let base metaclass do its memory allocation stuff
return BaseMetaClass.__new__(cls, name, bases, dct)
def __init__(cls, name, bases, dct):
# Do your custom initialization here, if any
# This, I assume, is where your catalog creation stuff takes place
# Now let base metaclass do its initialization stuff
super(DerivedMetaClass, cls).__init__(name, bases, dct)
If you don't have access to the definition of the metaclass for your third-party base class, you can replace BaseMetaClass
with enthought.traits.api.HasTraits.__metaclass__
. It's wordy, but it will work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With