Abstract Base Class を implement する NamedTuple は作れる?
例えば、以下のような抽象基底クラスがあったときに、それを実装するクラスを、 NamedTuple で実装したくなりました。 (より正確には、もともと NamedTuple だったクラスを抽象基底クラスの実装にしたくなった)
from abc import ABCMeta, abstractmethod
class Fooable(metaclass=ABCMeta):
@abstractmethod
def foo(self):
pass
これは、どうやったら実現できますでしょうか?
まず、単純に上記 Fooable
と NamedTuple を多重継承したクラスは、メタクラスが不一致なので作成できません。
from typing import NamedTuple, NamedTupleMeta
class Person(NamedTuple, Fooable):
age: int
name: str
# => TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
メタクラスの不一致が原因なので、両方を継承したメタクラスを作ってみると、今度はひとまずクラスの定義は完了し、実際にオブジェクトを作成することはできるものの、
- 実際に抽象基底クラスの抽象メソッドを実装しなくてもインスタンスを作成できてしまい、
isinstance
で抽象基底クラスのインスタンスであると判定されない
という性質があるため、これは、抽象クラスを用意することのメリットをほぼほぼ打ち消してしまうな、と思っています。特に、 mypy を用いる場合には、 isinstance
による条件分岐による型チェックは、これが正しく効かせられないとなると、わりと型を付与するメリットが、かなり減ってしまうなと思っています。
class NamedTupleABCMeta(ABCMeta, NamedTupleMeta):
pass
class FooablePerson(Fooable, NamedTuple, metaclass=NamedTupleABCMeta):
name: str
age: int
fooable_john = FooablePerson(name='John', age=30)
assert isinstance(fooable_john, Fooable)
# => AssertionError
質問
python3 において、抽象基底クラスを実装する、 NamedTuple を作成することはできますか?
再現可能なコード全体
from typing import NamedTuple, NamedTupleMeta
from abc import ABCMeta, abstractmethod
class Fooable(metaclass=ABCMeta):
@abstractmethod
def foo(self):
pass
class MyClass(Fooable):
pass
# my_obj = MyClass()
# => TypeError: Can't instantiate abstract class MyClass with abstract methods foo
# class Person(NamedTuple, Fooable):
# age: int
# name: str
#
# => TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
class NamedTupleABCMeta(ABCMeta, NamedTupleMeta):
pass
class FooablePerson(Fooable, NamedTuple, metaclass=NamedTupleABCMeta):
name: str
age: int
fooable_john = FooablePerson(name='John', age=30)
assert isinstance(fooable_john, Fooable)
# => AssertionError