@abstractmethod отлично работает без metaclass=ABCMeta, когда это не должно

Рассмотрим этот код

from abc import ABCMeta, abstractmethod

class C():
    @abstractmethod
    def my_abstract_method(self):
        print('foo')

class D(C):
    pass

x = C()
y = D()

Ни x, ни y не разрешены mypy, что дает мне

test.py:13: error: Cannot instantiate abstract class 'C' with abstract attribute 'my_abstract_method'
test.py:15: error: Cannot instantiate abstract class 'D' with abstract attribute 'my_abstract_method'

Я тестирую это с mypy 0.570 и python 3.6.3

Однако в документации сказано, что для этого мне нужно установить metaclass=ABCMeta. Что мне не хватает?


person Christoph    schedule 15.03.2018    source источник
comment
Какая версия питона? Я не могу воспроизвести это поведение ни на 2.7.x, ни на 3.4.3.   -  person bruno desthuilliers    schedule 15.03.2018
comment
Обновленный вопрос. Я получаю сообщение об ошибке с версией mypy 0.570. Кстати, я не получаю ошибок python напрямую, независимо от того, применяю ли я metaclass=ABCMeta или нет. Так что mypy — единственный инструмент, который действительно помогает мне поймать эту ошибку.   -  person Christoph    schedule 15.03.2018
comment
mypy и python делают две совершенно разные вещи. mypy — это статический анализатор, и он может сделать предположение, что вы забыли использовать ABCMeta, если @abstractmethod присутствует в исходном коде вашего кода. python просто интерпретирует код, и без ABCMeta у него нет причин что-либо делать со списком методов, заполненным @abstractmethod. (Действительно, во время выполнения в самом методе нет признаков того, что он был декорирован.)   -  person chepner    schedule 15.03.2018
comment
@chepner да, это правда. Просто так получилось, что я заметил, что mypy перехватывает ошибку без установленного metaclass, и я больше не проверял, что на самом деле делает python. Я просто остановился, задаваясь вопросом, почему mypy перехватывает ошибку, хотя я думал, что этого не должно быть. Спасибо за справочную информацию!   -  person Christoph    schedule 16.03.2018


Ответы (1)


Хорошо, получается, что без metaclass=ABCMeta только mypy поймает ошибку, тогда как с metaclass=ABCMeta и mypy, и python поймают ошибку.

Видеть:

from abc import abstractmethod

class C():
    @abstractmethod
    def my_abstract_method(self):
        print('foo')

class D(C):
    pass

x = C()
y = D()

$ mypy test.py 
test.py:13: error: Cannot instantiate abstract class 'C' with abstract attribute 'my_abstract_method'
test.py:15: error: Cannot instantiate abstract class 'D' with abstract attribute 'my_abstract_method'

но

$ python3 test.py
$

При этом python также поймает ошибку.

from abc import ABCMeta, abstractmethod

class C(metaclass=ABCMeta):
    @abstractmethod
    def my_abstract_method(self):
        print('foo')

class D(C):
    pass

x = C()

y = D()


$ python3 test.py 
Traceback (most recent call last):
  File "test.py", line 11, in <module>
    x = C()
TypeError: Can't instantiate abstract class C with abstract methods my_abstract_method
person Christoph    schedule 15.03.2018