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

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

```python
from abc import ABCMeta

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

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

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

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

    def punchline(self):
        raise NotImplementedError()

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

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

```python
sketch = ArgumentClinic() 
sketch.punchline() 

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

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

```python
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*!

```python
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
```

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

```python
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
```

<br>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://igor-19.gitbook.io/qa/avtomatizaciya-testirovaniya/python/oop-v-python-vo-vsekh-podrobnostyakh/abstraktnye-klassy.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
