参数化多个子功能的最佳实践

时间:2016-06-20 09:16:28

标签: python functional-programming

我经常遇到一种情况,我有一个顶级函数,我希望能够修改多个子函数的任何参数。我将以下面的例子表示:

def plot_data_processing(data_param_1=3, data_param_N=4,
        processing_param_1='a', processing_param_2='b', plotting_param_1='c',
        plotting_param_2=1324):
    data = get_data(data_param_1=data_param_1, data_param_1=data_param_N),
    processed_data = process_data(data, processing_param_1=processing_param_1, processing_param_2=processing_param_2)
    plot_data(processed_data, plotting_param_1=plotting_param_1, plotting_param_2=plotting_param_2)

现在,这有点难看,因为我不得不重新定义内部函数的所有默认值,而且我的参数是一个大问题。我想我可以做到以下几点:

def plot_data_processing(data_kwargs, processing_kwargs, plotting_kwargs):
    data = get_data(**data_kwargs),
    processed_data = process_data(data, **processing_kwargs)
    plot_data(processed_data, **plotting_kwargs)

plot_data_processing(dict(data_param_1=3, data_param_N=4), dict(processing_param_1='a', processing_param_2='b'), dict(plotting_param_1='c',plotting_param_2=1324))

但是,这并不是很好,因为我正在做这种通过dict传递参数的奇怪做法,他们只等待调用函数进行验证。看起来像是错误和不可读代码的配方。此外,我没有自由交换内部调用的函数用于具有类似接口的不同函数。所以我也可以去:

def plot_data_processing(data_getter, data_processor, plotter):
    data = data_getter(),
    processed_data = data_processor(data)
    plotter(processed_data)

class DataGetter(object):
    def __init__(self, data_param_1=3, data_param_N=4):
        self.data_param_1 = data_param_1
        self.data_param_N = data_param_N
    def __call__(self):
        # ....
        return data

# ... Also define classes DataProcessor and Plotter

plot_data_processing(DataGetter(data_param_1=3, data_param_N=4), DataProcessor(processing_param_1='a', processing_param_2='b'), Plotter(plotting_param_1='c',plotting_param_2=1324))

然而,这似乎也涉及不必要的结构和绒毛代码(self.x = x和所有这些)。我可以通过使用partials(或lambdas)来解决这个问题:

def plot_data_processing(data_getter, data_processor, plotter):
    data = data_getter(),
    processed_data = data_processor(data)
    plotter(processed_data)

# Called like:
plot_data_processing(
    data_getter = partial(get_data, data_param_1=3, data_param_N=4),
    data_processor = partial(process_data, processing_param_1='a', processing_param_2=3),
    plotter = partial(plot, plotting_param_1='c', plotting_param_2=1342),
    )

但这似乎也不令人满意 - 因为没有明确的“类型”参数来调用函数 - 只是一个部分函数应该在调用时起作用 - 使另一个想要使用该函数的程序员更难。 / p>

所以,这些方法都没有让我感到满足或快乐。我想我喜欢偏爱,但是我想要某种方式来声明部分函数服从某个接口。

有人知道更好的方法吗?

1 个答案:

答案 0 :(得分:1)

Python 3.5有一个新的(可选的)类型提示系统可能会做你想要的。 Python解释器在运行时不会检查它,但允许您创建有关参数类型和返回函数值的语句。可以在代码上运行单独的静态分析器程序,如mypy,以查找键入错误。

对于您的plot_data_processing功能,我认为您想宣布以下内容:

from typing import Callable, TypeVar

DataType = TypeVar("DataType")
ProcessedDataType = TypeVar("ProcessedDataType") # could be the same as DataType

def plot_data_processing(data_getter: Callable[[], DataType],
                         data_processor: Callable[[DataType], ProcessedDataType],
                         plotter: Callable[[ProcessedDataType], None]) -> None:
    ...

如果DataType函数使用与原始数据相同的类型返回相同的处理数据,则可能只能使用一个data_processer而不是两个Sequence[float]。您还可以更具体地指定这些类型(例如,使用TypeVar或其他类型,而不是使用link),如果您不需要通用方法。

有关详细信息,请参阅PEP 484和文档the typing module