【问题标题】:Is there a clean way to set conditional defaults to optional parameters in python functions?是否有一种干净的方法可以将条件默认值设置为 python 函数中的可选参数?
【发布时间】:2021-09-13 17:23:44
【问题描述】:

我有一个带有多个可选参数的函数,其默认值取决于非可选参数。

目前看起来是这样的:

def foo(x, y, option_1=None, option_2=None, option_3=None, option_4=None):
    if option_1 is None:
        option_1 = choose_option_1(x, y)

    if option_2 is None:
        option_2 = choose_option_2(x, y)

    if option_3 is None:
        option_3 = choose_option_3(x, y)

    if option_4 is None:
        option_4 = choose_option_4(x, y)

    return _foo(x, y, option_1, option_2, option_3, option_4)

但是这种风格打破了不重复代码的规则,而是使用循环。

所以我可以选择做这样的事情:

def foo_2(x, y, option_1=None, option_2=None, option_3=None, option_4=None):
    options = [option_1, option_2, option_3, option_4]
    funcs = [choose_option_1, choose_option_2, choose_option_3, choose_option_4]

    for i in range(len(options)):
        if options[i] is None:
            options[i] = funcs[i](x, y)

    return _foo(x, y, *options)

但是,我认为第二个选项实际上比第一个选项可读性差。

但无论哪种情况,我认为代码看起来都不必要地充实、沉重,比最佳代码更难理解。

是否有更简洁、更易读(也许更 Python 式)的替代方案?

编辑:如果你想自己运行这段代码,这里有一些你可以用来实现 foo 的占位符函数:

def choose_option_1(x, y):
    return x + y


def choose_option_2(x, y):
    return x - y


def choose_option_3(x, y):
    return x * y


def choose_option_4(x, y):
    return x / y


def _foo(x, y, option_1, option_2, option_3, option_4):
    return x + y + option_1 + option_2 + option_3 + option_4

【问题讨论】:

  • 现实生活中的答案是避免这种情况。我个人尝试完全避免使用默认参数,除非默认行为对于任何调用者来说都是真正显而易见的(例如排序函数中的key 参数是标识函数)。如果您的默认值是在运行时从其他输入中计算出来的,那么它可能不会很明显,这表明界面中存在一些更深层次的问题,但根据玩具示例无法诊断出它。鉴于设计,我认为代码很好,但代码的复杂性表明设计存在问题。
  • 有时,重复代码比替代代码更好。 DRY 是一个指导方针,而不是严格的规则。

标签: python python-3.x loops default-parameters


【解决方案1】:

我想如果是我,并且这是你经常遇到的模式,我可能会考虑重做 foo(),如果我可以使用部分。也就是说,您也可以使用类似于get() 的小实用函数来清理内容。如果可用则返回一个值,如果没有则返回一个备用值。请注意,我假设这些函数都比这个示例更复杂,否则我会将它们全部实现为 lambdas...

value_or_fallback = lambda value, fn, x, y: value if value is not None else fn(x,y)

def fallback_1(x, y):
    return x + y

def fallback_2(x, y):
    return x - y

def fallback_3(x, y):
    return x * y

def fallback_4(x, y):
    return x / y

def _foo(x, y, option_1, option_2, option_3, option_4):
    return x + y + option_1 + option_2 + option_3 + option_4

def foo(x, y, option_1=None, option_2=None, option_3=None, option_4=None):
    option_1 = value_or_fallback(option_1, fallback_1, x, y)
    option_2 = value_or_fallback(option_2, fallback_2, x, y)
    option_3 = value_or_fallback(option_3, fallback_3, x, y)
    option_4 = value_or_fallback(option_4, fallback_4, x, y)
    return _foo(x, y, option_1, option_2, option_3, option_4)

print(foo(1,2))
print(foo(1,2, option_4=75))

或者如果所有这些实用功能都/可以限定为foo(),那么我将使用闭包构建foo()

def build_foo():
    _get = lambda value, fn, x, y: value if value is not None else fn(x,y)
    _fb_1 = lambda x, y: x + y
    _fb_2 = lambda x, y: x - y
    _fb_3 = lambda x, y: x * y
    _fb_4 = lambda x, y: x / y
    _foo = lambda x, y, option_1, option_2, option_3, option_4: x + y + option_1 + option_2 + option_3 + option_4
    def foo(x, y, option_1=None, option_2=None, option_3=None, option_4=None):
        option_1 = _get(option_1, _fb_1, x, y)
        option_2 = _get(option_2, _fb_2, x, y)
        option_3 = _get(option_3, _fb_3, x, y)
        option_4 = _get(option_4, _fb_4, x, y)
        return _foo(x, y, option_1, option_2, option_3, option_4)
    return foo

foo = build_foo()
print(foo(1,2))
print(foo(1,2, option_4=75))

再次根据复杂性使用 lambda 或函数定义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-15
    • 2014-01-25
    • 2018-06-30
    相关资源
    最近更新 更多