简体   繁体   English

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

[英]Best practice for parametrizing multiple subfunctions

I often run into a situation where I have a top level function from which I want to be able to modify any of the parameters of multiple subfunctions. 我经常遇到这样的情况:我有一个顶层函数,希望从中修改多个子函数的任何参数。 I'll express this as the following example: 我将用以下示例来表示:

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)

Now, this is sort of ugly, because I'm forced to redefine all the defaults for my inner functions, and my parameters are one big mess. 现在,这有点丑陋,因为我被迫重新定义内部函数的所有默认值,而我的参数却一团糟。 I suppose I could do the following: 我想我可以做到以下几点:

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))

Still, this is not great, because I'm doing this odd practice of passing arguments via a dict, where they only wait for the function to be called to be validated. 不过,这并不好,因为我正在做这种奇怪的做法,即通过dict传递参数,在该dict中,它们仅等待调用函数被验证。 Seems like a recipe for bugs and unreadable code. 似乎像是关于错误和不可读代码的食谱。 Also, I have no freedom to swap the functions called internally for different functions with a similar interface. 另外,我没有自由用相似的接口将内部调用的函数交换为不同的函数。 So I could also go: 所以我也可以去:

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))

However this also seems to involve unnecessary structure and fluff code (self.x = x and all that). 但是,这似乎也涉及不必要的结构和绒毛代码(self.x = x等)。 I can get around that by using partials (or lambdas): 我可以通过使用局部变量(或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),
    )

But this also seems unsatisfying - because there is no clear "type" of arguments to call the function with - just a partial function which should work when called - makes it more difficult for another programmer who wants to use the function. 但这似乎也不令人满意-因为没有明确的参数“类型”来调用该函数-只是部分函数在被调用时应该起作用-使得想要使用该函数的另一个程序员更加困难。

So, none of these methods leave me feeling fulfilled or happy. 因此,这些方法都不会让我感到满足或高兴。 I guess I like partial, but I'd like some way to declare that a partial function obeys some interface. 我想我喜欢局部函数,但是我想以某种方式声明局部函数服从某些接口。

Does anybody know a better way? 有人知道更好的方法吗?

Python 3.5 has a new (optional) type hinting system that might do what you want. Python 3.5有一个新的(可选)类型提示系统,可以完成您想要的操作。 It's not checked at run-time by the Python interpreter, but does allow you to make statements about the types of arguments and return function values. Python解释器不会在运行时检查它,但确实允许您发出有关参数类型和返回函数值的语句。 A separate static analyzer program like mypy can be run on the code to look for typing errors. 可以在代码上运行像mypy这样的单独的静态分析器程序,以查找键入错误。

For your plot_data_processing function, I think you'd want to declare things something like this: 对于您的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:
    ...

You might be able to get away with only one DataType rather than two if the data_processer function returns the same the processed data using the same type as the original data. 如果data_processer函数使用与原始数据相同的类型返回相同的已处理数据,则可能只能使用一种DataType而不是两种。 You could also specify those types more specifically (eg with Sequence[float] or whatever, rather than using a TypeVar ) if you didn't need a generic approach. 如果不需要通用方法,也可以更具体地指定这些类型(例如,使用Sequence[float]或其他方法,而不是使用TypeVar )。

See PEP 484 and documentation the typing module for more details. 有关更多详细信息,请参见PEP 484和文档typing模块

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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