#eksperymenty #python
Ostatnio refaktorowałem trochę kodu w pracy. Mamy jeden proces, który regularnie się rozrasta o nowe zależności - Identyfikatory.
Każdy identyfikator jest w postaci oddzielnej klasy.
Żeby dodać nowy identyfikator z nową logiką identyfikacji, trzeba stworzyć nową klasę, zaimportować ją w innym module, wrzucić w tuple, która następnie jest iterowana -> Tworzy obiekt -> wywołuję metodę -> zwraca coś.
Zaczęło mnie to irytować, bo import i tupla regularnie rośnie i jest to taka robota głupiego...
Lubię eksperymentować, więc postanowiłem ubić tego potworka przy pomocy małego "metaprogrammingu" :D
Wjechała nowa abstrakcja:
class Identifier(ABC):
@classmethod
def identify(cls, schema):
for _cls in cls.__subclassess__():
if _type := _cls(schema)._identify(): return _type
return "NotSupportedType"
@abstractmethod
def _identify(self, schema) -> Optional[str]:
pass
Oczywiście każdy z identyfikatorów implementuje swoje własne metody dla konkretnego przypadku. Są one wywoływane we współdzielonym _identify
i zwracają co mają zwracać.
Oczywiście są pewne ryzyka w takim podejściu. Wystarczy, że jakiś śmieszek przedziedziczy po którymś z identyfikatorów i nagle subclasses hook zwróci dodatkową klasę :P
Anyway, moduł mocno się skurczył :) Hook wyciąga sobie klasy na podstawie __mro__
dzięki czemu nie trzeba tworzyć dodatkowego importu dla poszczególnych klas (I je gdzieś trzymać jako wsad dla iteratora...).
No to jest klasyka, innym sposobem jest skorzystanie z dekoratorów ale wiadome, że dochodzi wtedy konieczność dekorowania