Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can python metaclasses inherit?

classes can inherit..

class Base:
    def __init__(self,name):
        self.name = name

class Derived1(Base):
    def __init__(self,name):
        super().__init__(name)


class Derived2(Base):
    def __init__(self,name):
        super().__init__(name)

Can a similar thing done for meta classes also?

I have a requirement where some of my classes will have to be both abstract base classes and also my own meta classes (say singleton types..)

Is it possible to do

class Singleton(type): 
   '''
   implementation goes here..
   '''

class AbstractSingleton(Singleton,ABCMeta):
   '''
   What code should go here??
   '''

If its possible how to implement the AbstractSingleton class?

like image 675
Arun Kaliraja Baskaran Avatar asked Aug 31 '17 05:08

Arun Kaliraja Baskaran


1 Answers

Yes, it is possible.

But first things first:

You should not be using metaclasses for creating singletons in Python. Singletons are a simple concept, and just a custom __new__ method is enough - no need for a metaclass for that.

This simple 4 line normal class code can be used as a mixin, and will turn any derived classes into "singleton" classes - afer the first instance is created, no further instances are created, and the first instance is always returned:

class SingletonBase:
   def __new__(cls, *args, **kw):
        if not "instance" in cls.__dict__:
              cls.instance = super().__new__(cls, *args, **kw)
        return cls.instance

Now, if you'd have a real case for another metaclass and needed to combine that with ABCMeta or other metaclass, all you'd have to do is to create a third metaclass that inherits from both metaclasses - if both of them use super in a well behaved way, it would just work.

class SingletonMeta(type):
    def __call__(cls, *args, **kw):
         # You know - you _really_ should not be using metaclasses for singletons.
         if not "instance" in cls.__dict__:
             cls.instance = super().__call__(*args, **kw)
         return cls.instance


class SingletonAbstractMeta(SingletonMeta, abc.ABCMeta):
    pass

class SingleAbstractBase(metaclass=SingleAbstractMeta):
    ...

For sheer coincidence, earlier this week I used exactly this use case as an example of what can be achieved with a "meta meta class" in Python. By having a special "meta meta class" to the metaclass one wants to combine to another (I even use ABCMeta on the example), it can create the derived combined metaclass just by using the operator " + ", like in

class SingletonMeta(type, metaclass=MM):
    ...

class AbstractSingletonBase(metaclass=SingletonMeta + abc.ABCMeta):
    # code here.

Check the answer here.

like image 86
jsbueno Avatar answered Oct 30 '22 22:10

jsbueno