强制特定功能签名

时间:2016-03-10 09:54:24

标签: python parameter-passing overloading named-parameters

我刚刚发现自己编写了这样的代码:

def register(self, *,  # * enforces keyword-only parameters
             key_value_container:dict=None,    # legal parameter set #1
             key:str=None, value=None):        # legal parameter set #2

    # enforce one of the parameter sets
    if not ((key_value_container is not None and 
             key is None and value is None) or
            (key is not None and value is not None and 
             key_value_container is None)):
        raise TypeError('provide (key_value_container) or (key/value')

    # handle each legal parameter setf
    if key_value_container is not None:
        for _k, _s in key_value_container.items():
            self.register(_k, _s)
    else:
        do_something_with(key, value)

我的目标是拥有方法register()的两个签名:它应该是keyvalue或某个带有多个键和值的容器,例如dict

参数中的*至少迫使我提供命名参数,但不需要提供给定数量的参数甚至给定的一组参数< / em>的

当然,我可以(应该)提供两种不同名称和签名的方法,而不是一种。

但是如果我希望(有)提供一个具有多个参数语义的方法/函数 - 什么是使其可见并强制执行的最佳方法?

详细说明:

  • 是否可以在自动完成文档中明确哪些是合法的参数组合?
  • 如何检查(尽可能少的样板代码)是否提供了一个组合?

1 个答案:

答案 0 :(得分:1)

为了避免样板代码你可以这样:写下指定不同签名的附加函数。然后有一个redirect辅助函数,它根据参数匹配的签名将主函数的参数发送到附加函数。

它仍然不是特别优雅。如果概括了这一点,您还需要考虑如何处理None是您可能希望传递的有效参数的情况。

from inspect import getargspec
class Eg(object):
    def register(self, key_value_container=None, key=None, value=None):
        return redirect(locals(), [self.register_dict, self.register_single])

    def register_dict(self, key_value_container=None):
        print('register dict', key_value_container)

    def register_single(self, key=None, value=None):
        print('register single', key, value)

def redirect(params, functions):
    provided = {k for k, v in params.items() if v is not None}
    for function in functions:
        if set(getargspec(function).args) == provided:
            return function(**{k: params[k] for k in provided if k != 'self'})
    raise TypeError('wrong configuration provided') 
    # This error could be expanded to explain which signatures are allowed       

a = Eg()
a.register(key='hi', value='there')
a.register(key_value_container={'hi': 'there'})