Search code examples
pythonpython-3.6namedtupleabc

NamedTuple Class with ABC mixin


My problem is as follows: I want to create a class that inherits from typing.NamedTuple and another mixin which in an abstract class. Ideally I want to do something like this:

from typing import *
from abc import ABC, abstractmethod

class M(ABC):
    @abstractmethod
    def m(self, it: Iterable[str]) -> str:
        pass

class N(NamedTuple, M):
    attr1: str

    def m(self, it):
        return self.attr1 + it

When I try to do that now I get this error:

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

I know that I can do it this way:

from typing import *
from abc import ABC, abstractmethod

class M(ABC):
    @abstractmethod
    def m(self, it: Iterable[str]) -> str:
        pass

class NT(NamedTuple):
    attr1: str

class N(NT, M):
    def m(self, it):
        return self.attr1 + it

But I don't want to have to do that because it seems kinda gross and defines 2x the number of classes I am actually going to use. I am also looking for a solution that ideally changes M in some way, not something that I have to specify when creating N everytime.


Solution

  • You need to define a combined metaclass. In this case it's sufficient to make it the metaclass of M

    from typing import *
    from abc import ABCMeta, abstractmethod
    
    class NamedTupleABCMeta(ABCMeta, NamedTupleMeta):
        pass
    
    class M(metaclass=NamedTupleABCMeta):
        @abstractmethod
        def m(self, it: Iterable[str]) -> str:
            pass
    
    class N(NamedTuple, M):
        attr1: str
        def m(self, it):
            return self.attr1 + it