【问题标题】:How to pass a default value for argument from one function definition to a higher one如何将参数的默认值从一个函数定义传递到更高的函数定义
【发布时间】:2016-10-28 19:40:31
【问题描述】:

我正在寻找一种将参数的默认值传递给调用函数的好方法。让我通过例子来解释一下:

def greet(name, greeting='Hello', punctuation='!'):
    return greeting+' '+name+punctuation

def greet_with_hi(name, punctuation='!'):
   return greet(name, 'Hi', punctuation)

这是一个没有使用的示例,但这是我的问题:如何省略 greet_with_hipuncuation 参数的默认值?此参数的默认值已在 greet 中定义。

我能想到的解决方案:

  • 让它保持原样,缺点:必须在每个函数定义上更改默认值,而不是只在一个地方更改它
  • 使用None 作为默认参数的值并在greet 中处理None,缺点:特殊处理
  • 使用像DEFAULT_PUNCTUATION='!' 这样的全局“常量”并将其用作默认参数的值,缺点:似乎不是很pythonic

我还没有在 API 和其他代码中看到通用模式。您将如何处理这种模式?

【问题讨论】:

  • 您能否添加一个函数的示例用法并解释您期望的输出?
  • 你也可以创建一个装饰器,按照你喜欢的方式编排它。
  • @dmitryro:这个例子很简单,我有时不太清楚。构建一个足够灵活的装饰器有点棘手,但也许值得一试

标签: python


【解决方案1】:

让我们稍微简化一下您的问题。我们有两个函数,ab 正在使用它。

def a(arg = 0):
    return arg

def b(arg = 0):
    return a(arg)

并且您希望他们共享默认参数值。

您可以简单地创建一个全局变量并在两个定义中使用它:

__DEFAULT_VALUE = 0

def a(arg = __DEFAULT_VALUE):
    return arg

def b(arg = __DEFAULT_VALUE):
    return a(arg)

其他解决方案是将b 的默认参数设为None,然后对其进行检查。

def a(arg = 0):
    return arg

def b(arg = None):
    if arg is None:
        return a()
    return a(arg)

编辑:不要像下面的解决方案那样编码。时间不早了,我困了,原来是这么来的。

或者您可以使用更复杂和 pythoney 的方法。首先extract default arguments from the "base" a function,然后将b的默认值设置为None,并检查它是否被使用。如果是,则改用a 的默认值。

import inspect

def a(arg=0):
    return arg

def b(arg=None):
    if arg is None:
        signature = inspect.getargspec(a)
        unpacked_signature = dict(zip(signature.args[-len(signature.defaults):], signature.defaults))
        arg = unpacked_signature['arg']

    return a(arg)

【讨论】:

  • 哦,好的,我现在明白了。
  • @zondo 我认为编辑比删除更好-> 再次发布答案。但我可能错了(;
  • 好吧,看看新的答案,我想我有点过头了。
  • 那个编辑让我给你双重打击:不赞成和赞成。
  • 您的检查解决方案是一个非常糟糕的主意。这是运行时的反射,它非常昂贵、相当复杂,而且非常不必要,因为您已经通过简单地不传递默认值来触发它。因此,如果您已经进行了arg is None 检查,则只需调用不带参数的函数。
【解决方案2】:

为什么不使用None

def greet(name, greeting='Hello', punctuation='!'):
    return greeting+' '+name+punctuation

def greet_with_hi(name, punctuation=None):
    if punctuation:
        return greet(name, 'Hi', punctuation)
    else:
        return greet(name, 'Hi')

实际上任何特殊值都可以,但 None 在 if/else 上更好。

如果您希望"" 空字符串是有效的标点符号,您必须指定: if punctuation is not None:

通常,模式是包装器为包装函数中的强制参数设置默认值:

def greet(name, greeting, punctuation):
    return greeting+' '+name+punctuation

def greet_with_hi(name, punctuation='!'):
   return greet(name, 'Hi', punctuation)

这个想法是greet() 是一般情况,greet_with_hi 会为您完成一些工作。

【讨论】:

  • 如果不需要标点符号怎么办?不能做greet_with_hi(name, '') 因为'' 是假的。我建议使用 isis not None 而不是依赖其布尔值。
  • 真实故事。话虽这么说,我想这取决于没有标点符号的问候语是否有效......以及空字符串是否应该触发默认标点符号。当我们进行默认字符串操作时,我们总是使用空字符串作为默认值 > punctuation='' 然后只使用 if punctuation 因为它更干净,但你是对的,他可能希望能够使用空字符串。已更新。
  • 虽然我同意仅将默认参数放在包装函数上是一个很好且简单的解决方案,但请注意,这不一定总是有效。被包装的函数不一定知道它正在被包装,所以仅仅因为它被包装,删除默认参数可能不是一个好的解决方案。还要考虑一旦你想再次包装 greet_with_hi 会发生什么,然后你又回到了起点并且没有解决方案,因为你不想让该函数的参数成为非默认值。
【解决方案3】:

无需修改您的greet 函数,您可以简单地从greet_with_hi 函数中删除参数并且不为参数传递任何内容。这样,greet 上定义的默认值将被使用:

def greet_with_hi(name):
    return greet(name, 'Hi')

如果您希望能够使用greet_with_hipunctuation 指定不同的值,但仍希望使用greet 上指定的默认值,否则您可以这样做:

def greet_with_hi(name, punctuation = None):
    if punctuation is None:
        return greet(name, 'Hi')
    else:
        return greet(name, 'Hi', punctuation)

不幸的是,没有值可以传达“使用默认值”的含义,因此您只能通过不向其传递参数来从 greet 触发默认值。

或者,您也可以在此处使用元组解包,因此您只需在此处指定一次参数。但是,当您有多个默认参数时,这可能更有意义——此时您可能也想使用命名参数):

def greet_with_hi(name, punctuation = None):
    additionalArgs = []
    if punctuation is not None:
        additionalArgs.append(punctuation)
    return greet(name, 'Hi', *additionalArgs)

【讨论】:

  • 我喜欢这样更健壮,但在这种情况下,我认为不需要额外的力量。话虽如此,我认为其他可能需要额外功能的人可能会发现这个问题。您还可以添加代码以“使用默认值”:标点符号的所有有效输入都是字符串,因此,您可以使用不是字符串的任何内容将信息传递回包装函数...def greet_with_hi(name, punctuation = <any number>) 和 greet 可以检查 @ 987654332@,然后在else处理特殊情况。
  • @TemporalWolf 我看不出greet_with_hi('foo', 5)gree_with_hi('foo', None) 更能表达什么意思。 None 实际上是触发默认情况的一个很好且被广泛接受的值。
  • @TemporalWolf 另外,当 OP 将他的示例描述为 “一个没有用的示例”。因此,他的用例可能不那么琐碎,只是在寻求一般模式。
猜你喜欢
  • 2011-08-26
  • 2021-10-17
  • 1970-01-01
  • 2019-04-02
  • 1970-01-01
  • 1970-01-01
  • 2018-07-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多