環境
- Python 3.11.2
概要
abc.ABC
を継承し忘れて、抽象基底クラスとして書いてしまうときがたまにあります。
ただその場合でも、問題なく動いていたりします。
abc.ABC
を継承するとどうなるのか、なぜabc.ABC
を継承する必要があるのかが分かっていなかったので、abc.ABC
を継承する/しないによって挙動がどのように変わるかを調べました。
理想の状態
Dog
クラスは具象クラスですが、cry
メソッドの実装が漏れている状態です。
import abc
class Animal(abc.ABC):
@abc.abstractmethod
def cry(self) -> None:
pass
class Dog(Animal):
# def cry(self) -> None:
# print("bowwow")
def only_dog_method(self) -> None:
print("only dog method")
dog = Dog()
$ python sample.py
Traceback (most recent call last):
File "/home/vagrant/Documents/study/20230503/sample.py", line 18, in <module>
dog = Dog()
^^^^^
TypeError: Can't instantiate abstract class Dog with abstract method cry
$ mypy sample.py
sample.py:18: error: Cannot instantiate abstract class "Dog" with abstract attribute "cry" [abstract]
Found 1 error in 1 file (checked 1 source file)
python、mypy1でエラーが発生しました。
抽象メソッドは宣言しているが、abc.ABC
を継承していない
import abc
class Animal:
@abc.abstractmethod
def cry(self) -> None:
pass
class Dog(Animal):
# def cry(self) -> None:
# print("bowwow")
def only_dog_method(self) -> None:
print("only dog method")
dog = Dog()
$ python sample1.py
$ mypy sample1.py
sample1.py:18: error: Cannot instantiate abstract class "Dog" with abstract attribute "cry" [abstract]
Found 1 error in 1 file (checked 1 source file)
python実行時にはエラーは発生しませんでした。
公式ドキュメントには、abc.abstractmethod
について以下のように記載されています。
このデコレータを使うには、クラスのメタクラスが ABCMeta かそれを継承したものである必要があります。 ABCMeta の派生クラスをメタクラスに持つクラスは、全ての抽象メソッドとプロパティをオーバーライドしない限りインスタンス化することができません。2
abc.ABC
を継承していないクラスはabc.abstractmethod
デコレータを使う条件を満たしていないため、Python実行時にエラーは発生しなかったようです。
mypyは、abc.abstractmethod
を利用していれば抽象基底クラスだとみなして、エラーを出力しているのかもしれません。
抽象メソッドがないクラスでabc.ABC
を継承する
Animal
クラスをmixinクラスとして扱いたいです。Animal
クラスはインスタンス化させたくありません。Animal
は抽象クラスではありません(抽象メソッドが存在しない)が、abc.ABC
を継承してみました。
import abc
class Animal(abc.ABC):
def cry(self) -> None:
print("cry, cry")
class Dog(Animal):
def only_dog_method(self) -> None:
print("only dog method")
animal = Animal() # インスタンス化を禁止させたい
dog = Dog()
$ python sample2.py
$ mypy sample2.py
Success: no issues found in 1 source file
python, mypyでエラーは発生しませんでした。
そもそもDog
もabc.ABC
のサブクラスなので、abc.ABC
を継承したらインスタンス生成を禁止できる訳がないですね。。。
issubclass(Dog, abc.ABC) # => True
issubclass(Animal, abc.ABC) # => True
-
mypyはインスタンス化しないと、抽象メソッドの実装漏れのエラーは発生しません。https://qiita.com/yuji38kwmt/items/1000adfadc7faea7d0ea ↩
-
https://docs.python.org/ja/3.11/library/abc.html#abc.abstractmethod ↩