Wie stellt man typsichere Factory-Funktionen für dynamisch registrierte Klassen in Python bereit?Python

Python-Programme
Anonymous
 Wie stellt man typsichere Factory-Funktionen für dynamisch registrierte Klassen in Python bereit?

Post by Anonymous »

TL;DR
Angenommen, eine Python-Bibliothek definiert eine Schnittstelle, die durch Code von Drittanbietern implementiert werden soll. Wie könnte diese Bibliothek eine Factory-Funktion bereitstellen, die Instanzen dieser Implementierungen mit angemessener statischer Typsicherheit erstellt?

Beispiel
Betrachten wir zur Veranschaulichung ein Minimalbeispiel mit Formen.
Die Bibliothek definiert ein Protokoll für Formen und stellt eine Factory-Funktion bereit, die Instanzen (entweder integrierte oder von Drittanbietern) basierend auf einem Zeichenfolgenschlüssel und einem Weiterleitungskonstruktor erstellt Argumente.
Implementierungen können unterschiedliche Konstruktorparameter haben.

Code: Select all

# 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)
Und einige integrierte Formen:

Code: Select all

# 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)
Verwendungsbeispiel:

Code: Select all

shape1 = create_shape("circle", radius=1)
shape2 = create_shape("square", side=2)
Zur Laufzeit funktioniert das perfekt.
Ich möchte jedoch statische Typhinweise bereitstellen, damit:
  • Der Rückgabetyp von create_shape("circle", radius=1) als Kreis abgeleitet wird
  • Die Schlüsselwortargumente radius und side werden vom Typprüfer validiert
  • Pakete von Drittanbietern können neue Formen registrieren (z. B. Rechteck, Dreieck), ohne die Kernbibliothek zu ändern
Bisher besteht der einzige typsichere Ansatz, den ich gefunden habe, darin, @overload-Definitionen für bekannte Formen hinzuzufügen, aber das lässt sich offensichtlich nicht für Erweiterungen von Drittanbietern skalieren.

Frage:
Gibt es eine Möglichkeit, eine dynamisch erweiterbare Factory-Funktion wie diese typsicher zu machen, sodass statische Typprüfer (wie mypy oder pyright) weiterhin die richtigen Konstruktorparameter und Rückgabetypen ableiten können – auch für von Drittanbietern registrierte Klassen?
Müsste ich:
  • die Registrierung oder das Factory-Muster neu entwerfen?
  • Verwenden Sie a TypedDictbasiertes Parametersystem?
  • Oder ist das nur mit einem benutzerdefinierten Mypy-Plugin möglich?
Ich bin sowohl für Lösungen auf Designebene als auch für Typsystemlösungen offen.

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post