Как обеспечить типобезопасные фабричные функции для динамически зарегистрированных классов в Python?Python

Программы на Python
Ответить
Anonymous
 Как обеспечить типобезопасные фабричные функции для динамически зарегистрированных классов в Python?

Сообщение Anonymous »

TL;DR
Предположим, библиотека Python определяет интерфейс, предназначенный для реализации сторонним кодом. Как эта библиотека может предоставить фабричную функцию, которая создает экземпляры этих реализаций с надлежащей статической безопасностью типов?

Пример
Рассмотрим библиотеку, которая определяет протокол для фигур и предоставляет фабричную функцию, которая создает экземпляры (встроенные или сторонние) на основе строкового ключа и пересылает аргументы конструктора.
Реализации могут иметь разные конструкторы параметры.

Код: Выделить всё

# core.py
from typing import Protocol, Any

class Shape(Protocol):
def area(self) -> float: ...
def perimeter(self) -> float: ...

SHAPE_REGISTRY: dict[str, type[Shape]] = {}

def register_shape(name: str, cls: type[Shape]) -> None:
SHAPE_REGISTRY[name] = cls

def create_shape(kind: str, **kwargs: Any) -> Shape:
cls = SHAPE_REGISTRY[kind]
return cls(**kwargs)
И несколько встроенных фигур:

Код: Выделить всё

# shapes.py
from core import Shape, register_shape

class Circle:
def __init__(self, radius: float):
self.radius = radius
def area(self) -> float: return 3.14 * self.radius ** 2
def perimeter(self) -> float: return 2 * 3.14 * self.radius

class Square:
def __init__(self, side: float):
self.side = side
def area(self) -> float: return self.side ** 2
def perimeter(self) -> float: return 4 * self.side

register_shape("circle", Circle)
register_shape("square", Square)
Пример использования:

Код: Выделить всё

shape1 = create_shape("circle", radius=1)
shape2 = create_shape("square", side=2)
Во время выполнения это работает отлично.
Однако я хотел бы предоставить подсказки статического типа, чтобы:
  • Тип возвращаемого значения create_shape("circle", radius=1) выводился как Circle
  • Аргументы ключевых слов radius и Side проверялись средством проверки типов
    />
  • Сторонние пакеты могут регистрировать новые фигуры (например, Rectangle, Triangle) без изменения базовой библиотеки
Пока единственный найденный мною типобезопасный подход — это добавить определения @overload для известных фигур, но он, очевидно, не масштабируется для сторонних расширений.

Вопрос:
Есть ли способ сделать динамически расширяемую фабричную функцию, подобную этой, типобезопасной, чтобы средства проверки статических типов (такие как mypy илиpyright) могли по-прежнему выводить правильные параметры конструктора и возвращаемые типы, в том числе для классов, зарегистрированных сторонними организациями?
Нужно ли мне:
  • Перепроектировать реестр или фабрику шаблон?
  • Использовать систему параметров на основе TypedDict?
  • Или это возможно только с помощью специального плагина mypy?
Я открыт как для решений на уровне дизайна, так и для систем типов.

Подробнее здесь: https://stackoverflow.com/questions/798 ... classes-in
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»