0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

`abc.ABC`を継承するかしないかで、インスタンス生成時の挙動をpythonとmypyで確認した

Posted at

環境

  • Python 3.11.2

概要

abc.ABCを継承し忘れて、抽象基底クラスとして書いてしまうときがたまにあります。
ただその場合でも、問題なく動いていたりします。
abc.ABCを継承するとどうなるのか、なぜabc.ABCを継承する必要があるのかが分かっていなかったので、abc.ABCを継承する/しないによって挙動がどのように変わるかを調べました。

理想の状態

Dogクラスは具象クラスですが、cryメソッドの実装が漏れている状態です。

sample.py
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を継承していない

sample1.py
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を継承してみました。

sample2.py
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でエラーは発生しませんでした。
そもそもDogabc.ABCのサブクラスなので、abc.ABCを継承したらインスタンス生成を禁止できる訳がないですね。。。

issubclass(Dog, abc.ABC) # => True
issubclass(Animal, abc.ABC) # => True
  1. mypyはインスタンス化しないと、抽象メソッドの実装漏れのエラーは発生しません。https://qiita.com/yuji38kwmt/items/1000adfadc7faea7d0ea

  2. https://docs.python.org/ja/3.11/library/abc.html#abc.abstractmethod

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?