【问题标题】:Force specific function signatures强制特定的函数签名
【发布时间】:2016-06-25 02:14:46
【问题描述】:

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

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

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

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

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

详细说明:

  • 是否可以在auto-completiondocumentation中明确哪些是合法的参数组合?
  • 如何检查(尽可能少的样板代码)是否提供了一种组合?

【问题讨论】:

  • 那么你基本上是想在Python中实现多态方法?
  • 对我来说,有一种优雅的方式来检查和传达一些约束就足够了。 Python 已经检查了您提供 固定数量 个参数的情况的一致性(并且它还检查 最大 个参数)。但事实上,这至少非常接近多态方法/函数。
  • 您可以使用装饰器实现一些东西来执行此操作(从单个名称分派到多个实现),但这可能不会与自动完成等配合得很好,因为您实际调用的方法会有任意的*args, **kwargs 接口。

标签: python parameter-passing overloading named-parameters


【解决方案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'})

【讨论】:

  • 这很好,因为您仍然拥有复合签名(API 定义可能需要)和显式专业化,而样板代码是外包的(非常无聊:))
  • 这对你有用吗?我不得不从 argspec 中减去 self-set
  • 如果None 没有设置合适的默认值,您可以创建自己的对象(例如_DEFAULT=object()def my_func(x=_DEFAULT)),它可以实现相同的功能,但没有风险其他含义。
  • @frans 你说得对,我现在已经调整了 selfprovided 中,但在将参数传递给函数之前被删除了。
猜你喜欢
  • 2019-08-14
  • 1970-01-01
  • 1970-01-01
  • 2021-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多