from abc import ABC, abstractmethod
class Interface(ABC):
    @abstractmethod
    def do_something(self):
        pass
class Implementation(Interface):
    def do_something(self):
        print("Implementation doing something")
def use_interface(obj: Interface):
    obj.do_something()
obj = Implementation()
use_interface(obj)
  В Python, благодаря его динамической типизации, концепция интерфейсов реализуется через полиморфизм, а не через строгую реализацию интерфейсов, как в языках вроде Java или C#. Основная идея заключается в том, что объекты разных классов могут использоваться взаимозаменяемо, если они предоставляют одинаковый набор методов (имеют "утиную типизацию" - "если он ходит как утка и крякает как утка, то это утка").
Основные способы создания интерфейсов с использованием полиморфизма в Python:
AttributeError во время выполнения.  Это гибкий, но менее строгий подход.
            
class Bird:
    def fly(self):
        print("Птица летит")
class Airplane:
    def fly(self):
        print("Самолёт летит")
def make_it_fly(flyable):
    try:
        flyable.fly()  # Предполагаем, что объект имеет метод fly()
    except AttributeError:
        print("Объект не умеет летать")
bird = Bird()
airplane = Airplane()
make_it_fly(bird)      # Вывод: Птица летит
make_it_fly(airplane)  # Вывод: Самолёт летит
class Rock:
    pass  #У объекта нет метода fly
rock = Rock()
make_it_fly(rock) #Вывод: Объект не умеет летать
            abc:  Модуль abc предоставляет способ определить абстрактные классы и абстрактные методы.  Абстрактные классы не могут быть инстанцированы, и их подклассы должны реализовать все абстрактные методы, иначе Python выбросит исключение TypeError при попытке создать экземпляр подкласса.  Это более строгий способ, чем duck typing.
           
from abc import ABC, abstractmethod
class Flyable(ABC):
    @abstractmethod
    def fly(self):
        pass
class Bird(Flyable):
    def fly(self):
        print("Птица летит")
class Airplane(Flyable):
    def fly(self):
        print("Самолёт летит")
# Создание экземпляра Flyable напрямую невозможно:
# flyable = Flyable()  # TypeError: Can't instantiate abstract class Flyable with abstract methods fly
bird = Bird()
bird.fly() #Вывод: Птица летит
#Класс, не реализующий абстрактный метод, вызовет ошибку при инстанциации:
class BadBird(Flyable):
  pass
#bad_bird = BadBird() # TypeError: Can't instantiate abstract class BadBird with abstract methods fly
            isinstance() или issubclass() для проверки типов, но это менее распространено и часто считается не-питоническим.  В основном используется для обработки особых случаев.  Это обычно избегают, так как это нарушает принципы полиморфизма и duck typing.Пример обобщенного кода:
def process_data(data_source):
    data = data_source.load_data()  # Предполагаем, что data_source имеет метод load_data()
    processed_data = some_processing(data)
    data_source.save_data(processed_data) # Предполагаем, что data_source имеет метод save_data()
class FileDataSource:
    def load_data(self):
        print("Загрузка данных из файла")
        return "Данные из файла"
    def save_data(self, data):
        print(f"Сохранение данных в файл: {data}")
class DatabaseDataSource:
    def load_data(self):
        print("Загрузка данных из базы данных")
        return "Данные из базы данных"
    def save_data(self, data):
        print(f"Сохранение данных в базу данных: {data}")
def some_processing(data):
    print("Обработка данных")
    return f"Обработанные данные: {data}"
file_data_source = FileDataSource()
database_data_source = DatabaseDataSource()
process_data(file_data_source)    # Работает с FileDataSource
process_data(database_data_source) # Работает с DatabaseDataSource
    Заключение:
Выбор между duck typing и ABC зависит от конкретной ситуации. Duck typing обеспечивает большую гибкость, но ABC обеспечивает более строгий контроль и лучшую читаемость кода, особенно в больших проектах.