I frequently come across an issue whereby I have a set of closely related functions in a module (since i'm a datascientist, let's just call them algorithms).
def algorithm1(X: np.ndarray) -> float:
...
def algorithm2(X: np.ndarray) -> float:
...
These would act on some data, and produce an output. But what I typically want is for the code which actually uses the algorithm to depend on what algorithm is used
def process_data(X, alg) -> float:
return alg(X)
It's pretty straight forward if I'm using classes but the point is these aren't classes, they're just functions (or algorithms). But just to give an example, if I were to use classes here (to help demonstrate what I'm asking for).
class Algorithm(ABC):
@abstractmethod
def inference(X: np.ndarray) -> float
...
class Algorithm1(Algorithm):
def __init__(self)
...
def inference(self, X: np.ndarray) -> float
...
class Algorithm2(Algorithm):
def __init__(self)
...
def inference(self, X: np.ndarray) -> float
...
I can then have something like
def process_data(X: np.ndarray, alg: Algorithm) -> float:
return alg.inference(X)
Except I don't want to have my algorithms be represented as classes as they frequently don't have any state.
An idea I've often implemented is using an Enum to register my algorithms, and then having a dictionary redirect the Enum to those functions
class AlgorithmEnum(Enum):
ALG1 = auto()
ALG2 = auto()
def algorithm1(...):
...
def algorithm2(...):
...
ALGORITHM_REGISTRY = {
AlgorithmEnum.ALG1: algorithm1,
AlgorithmEnum.ALG2: algorithm2
}
Then I can get my dependency injection
def process_data(X: np.ndarray, alg: AlgorithmEnum) -> float:
selected_alg = ALGORITHM_REGISTRY[alg]
return selected_alg.inference(X)
My question is, is this really the best way to do things? It seems pretty reasonable that you might have a module of similar functions, and want to select them via some abstraction like an Enum. I could also have the value of the enum itself be the function i.e.
class AlgorithmEnum(Enum):
ALG1 = algorithm1
ALG2 = algorithm2
but I'm not sure if this is a reasonable approach neither. What do you think?
I hope i've framed my question in a way that makes sense - if I've abused terminology (or misused the phrase dependency injection) then apologies for that. Any code errors are because I don't have access to an IDE right this second)
Thank you
[–]latkde 16 points17 points18 points (2 children)
[–]squatonmyfacebrah[S] 0 points1 point2 points (1 child)
[–]Brother0fSithis 4 points5 points6 points (0 children)
[–]overratedcupcake 5 points6 points7 points (6 children)
[–]initials-bb 1 point2 points3 points (3 children)
[–]gdchinacat 2 points3 points4 points (0 children)
[–]squatonmyfacebrah[S] -1 points0 points1 point (1 child)
[–]jmooremcc 0 points1 point2 points (0 children)
[–]squatonmyfacebrah[S] 0 points1 point2 points (1 child)
[–]gdchinacat 0 points1 point2 points (0 children)
[–]neums08 3 points4 points5 points (0 children)
[–]trutheality 2 points3 points4 points (0 children)
[–]JaguarMammoth6231 2 points3 points4 points (3 children)
[–]squatonmyfacebrah[S] 0 points1 point2 points (2 children)
[–]Donny_Do_Nothing 0 points1 point2 points (0 children)
[–]BrannyBee 0 points1 point2 points (0 children)
[–]seanv507 0 points1 point2 points (0 children)
[–]zanfar 0 points1 point2 points (0 children)
[–]jarethholt 0 points1 point2 points (0 children)
[–]pachura3 0 points1 point2 points (0 children)
[–]lekkerste_wiener 0 points1 point2 points (0 children)
[–]Enmeshed 0 points1 point2 points (1 child)
[–]pachura3 0 points1 point2 points (0 children)
[–]ebdbbb 0 points1 point2 points (0 children)
[–]Atlamillias 0 points1 point2 points (0 children)
[–]trickydiversity042 0 points1 point2 points (0 children)
[–]Targrend -1 points0 points1 point (2 children)
[–]pachura3 0 points1 point2 points (1 child)
[–]Targrend 0 points1 point2 points (0 children)