首页 > 解决方案 > Design pattern for implementing different "bundles" of functions in Python 3.6

问题描述

so I have a set of distance functions and respective calculations, e.g. 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

标签: pythondesign-patternspython-3.6

解决方案


看来您需要的是简单的继承。因此,您创建了一个BaseSpace基本上是接口的基类:

from abc import ABC

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

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

然后,您只需使用所需功能的所有不同组合继承此接口,在类内部(如果您只使用一次)或外部实现方法,并在类定义中分配它们:

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

    mean = staticmethod(np.mean)

由于 Python 的鸭子类型方法(也适用于接口定义),您实际上并不需要实际定义的基类,但它有助于显示每个“空间”类的预期。


推荐阅读