Абстрактные классы

Абстрактные классы - это классы, которые предназначены для наследования, но избегают реализации конкретных методов, оставляя только сигнатуры методов, которые должны реализовывать подклассы.

from abc import ABCMeta

class AbstractClass(object):
    # атрибут метакласса всегда должен 
    # быть установлен как переменная класса 
    __metaclass__ = ABCMeta

   # декоратор abstractmethod регистрирует этот метод как undefined
   @abstractmethod 
   def virtual_method_subclasses_must_define(self):
       # Можно оставить полностью пустым
       # или предоставить базовую реализацию
       # Обратите внимание, что обычно пустая интерпретация
       # неявно возвращает `None`, но при регистрации
       # это поведение больше не применяется.
123456789101112131415

Причины использования абстрактных классов

class MontyPython:
    def joke(self):
        raise NotImplementedError()

    def punchline(self):
        raise NotImplementedError()

class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"
12345678910

Когда мы создаем объект и называем это два метода, мы получим ошибку (как и ожидалось) с punchline() метод.

sketch = ArgumentClinic() 
sketch.punchline() 

# AttributeError: 'ArgumentClinic' object has no attribute 'punchline'
1234

Этого можно избежать, используя модуль Abstract Base Class (ABC).

from abc import ABCMeta, abstractmethod
class MontyPython(metaclass=ABCMeta):
  @abstractmethod
  def joke(self):
    pass
  @abstractmethod
  def punchline(self):
  	pass

# у наследуемого класса 2 @abstractmethod, а мы использовали только один
class ArgumentClinic(MontyPython):
  def joke(self):
    return "Hahahahahah"

c = ArgumentClinic()
# TypeError: "Can't instantiate abstract class ArgumentClinic with abstract methods punchline"
12345678910111213141516

На этот раз, когда мы пытаемся создать экземпляр объекта из неполного класса, мы немедленно получаем TypeError!

class ArgumentClinic(MontyPython):
  def joke(self):
    return "Hahahahahah"
  
  def punchline(self):
    return "Send in the constable!"

c = ArgumentClinic()
c  

# <__main__.ArgumentClinic object at 0x7fee680d3640>
1234567891011

Простой пример с множественным наследованием

class A(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def do(self):
        pass

class B(object):
    def do(self):
        print "do"

class C(B, A):
    pass

c = C()
123456789101112131415

Last updated