Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python ABC Multiple Inheritance

I think the code will explain the problem better than I can do with words. Here is the code in my_abc.py:

from abc import ABCMeta, abstractmethod

class MyABC(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def print(self):
        pass

Here is the code in my_class.py

from my_abc import MyABC
from third_party_package import SomeClass

class MyClass(MyABC, SomeClass):
    def __init__(self):
        super(MyClass, self).__init__()

    def print(self):
        print('Hello ABC')

When I try to run my_class.py I get:

TypeError: Error when calling the metaclass bases metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

I understand that I can create a class the inherits directly from my interface MyABC, and then create another class which then inherits from both this class which I created and my third party module class.

My question is: Is there another better and proper way of doing this directly without having to create an intermediate class for my purpose?

like image 625
moeabdol Avatar asked Mar 01 '15 21:03

moeabdol


Video Answer


2 Answers

The SomeClass class has a custom metaclass. You will need to create a metaclass which inherits from both ABCMeta and this custom metaclass, then use it as the metaclass for MyClass. Without knowing more about this custom metaclass, I cannot determine a correct way to do this in the general case, but it will probably look like one of these possibilities:

class DerivedMeta(ABCMeta, type(SomeClass)):
    pass

class DerivedMeta(type(SomeClass), ABCMeta):
    pass

It's unlikely but possible you will also need to override one or more methods to ensure correct metaclass interactions.

like image 126
Kevin Avatar answered Oct 07 '22 17:10

Kevin


Thread is still at the top in search result, so I wanted to share my complete solution.
I ran into this problem when trying to create an abstract template class meant to PyQt5 widgets, in Python 3.8. I applied @Kevin's solution, creating a new meta class first. The working code:

from abc import ABC, ABCMeta
from PyQt5.QtWidgets import QWidget, QLabel


class QABCMeta(ABCMeta, type(QWidget)):
    """Create a meta class that combines ABC and the Qt meta class"""
    pass


class TcWidget(ABC, metaclass=QABCMeta):
    """Abstract class, to be multi-inherited together with a Qt item"""
    pass


class TcLabel(QLabel, TcWidget):
    """Label that shows a value"""
    pass


# ...
label = TcLabel()
# ...
like image 5
Roberto Avatar answered Oct 07 '22 16:10

Roberto