简体   繁体   中英

Design pattern for implementing different “bundles” of functions in Python 3.6

so I have a set of distance functions and respective calculations, eg average, comparison

and I want to be able to iterate over those different distances to compute their values/averages/whatevers, and make it easy to add new distances

Right now, I'm doing that by using nested dictionaries, however this depends on all the functions existing and working properly, so I was wondering whether there is a design pattern that solves that?

My first idea was a metaclass that defines which functions need to exist and classes that implement these functions. However, then there would be no meaningful instances of those Distance classes. My second idea then was defining a Distance class and have the functions as attributes of that class, but that seems bad style. Example for the second Idea:

class Distance:
    def __init__(self, distf, meanf):
        self.distf = distf
        self.meanf = meanf

    def dist(self, x1,x2):
        return self.distf(x1,x2)

    def mean(self, xs):
         return self.meanf(xs)

    d = Distance(lambda x,y: abs(x-y), np.mean)

    d.dist(1,2) ##returns 1 as expected
    d.dist([1,2]) ## returns 1.5 as expected

this works (and also enforces the existence/maybe even properties of the functions), but as stated above feels like rather bad style. I do not plan to publish this code, its just about keeping it clean and organized if that is relevant. I hope the question is clear, if not pleas dont hesitate to comment and I will try to clarify.

EDIT: - @victor: Everything should be initially set. At runtime only selection should occur. - @abarnert Mostly habitual, also to restrict usage (np.mean needs to be called without axis argument in this example), but that should hopefully not be relevant since I'm not publishing this - @juanpa gonna look into that

It seems that simple inheritance is what you need. So, you create a base class BaseSpace which is basically an interface:

from abc import ABC

class BaseSpace(ABC):
    @staticmethod
    def dist(x1, x2):
        raise NotImplementedError()

    @staticmethod
    def mean(xs):
        raise NotImplementedError()

Then you just inherit this interface with all different combinations of the functions you need, implementing the methods either inside the class (if you are using them once only) or outside, and just assigning them in the class definition:

class ExampleSpace(BaseSpace):
    @staticmethod
    def dist(x1, x2):
        return abs(x1 - x2)

    mean = staticmethod(np.mean)

Because of the Python's duck typing approach (which is also applicable to interface definition) you don't really need the base class actually defined, but it helps to show what is expected of each of your "Space" classes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM