【问题标题】:What is a good way to get a function to use its default value for an argument when the argument is specified as None in Python?当参数在 Python 中指定为 None 时,让函数使用其默认值作为参数的好方法是什么?
【发布时间】:2015-02-26 08:55:26
【问题描述】:

假设我有一个函数(称为function),它接受一个默认值为True 的布尔参数,例如def function(argument1 = True)

现在假设我想使用这个函数,使用另一个函数 (resolveArg) 的输出来指定它的参数,该函数检查现有基础架构中的参数。这个resolveArg 方法通常使用,如果它可以找到发往给定函数的参数值(例如function),则将函数参数设置为它,否则将参数设置为None

如果其他函数 (resolveArg) 将 None 的参数设置为 None,如何让 function 使用其参数的默认值?

def resolveArg(argName = None):
    if argName in self.conf._argdict:
        return(self.conf._argdict[argName].value)
    else:
        return(None)

def function(argument1 = True)
    if argument1 is True:
        return(True)
    elif argument1 is False:
        return(False)
    else:
        raise(Exception)

function(argument1 = resolveArg("red"))

【问题讨论】:

  • 我不认为有一个内置功能允许这样做,事实上,如果你传递 None 你已经传递了一个 'NoneType' 的对象,所以不会使用默认值
  • 嗯...似乎有点过度设计...我认为function实际上在做比这更复杂的事情?

标签: python function default-arguments


【解决方案1】:

警告

您要求“当参数在 Python 中指定为 None 时,让函数使用其默认值作为参数的好方法?”

我认为没有好的方法,因为这不是一件好事。这是一件有风险的事情——它可以掩盖令人讨厌的错误情况,在这些情况下,您可能合理地希望检测到 None 在您期望值的位置传递的事实。在广泛使用这种技术的地方进行调试可能会很糟糕。 谨慎使用。

可能的方法

我猜您想要一个通用的解决方案,该解决方案将适用于比您作为示例提供的功能更多的功能。在示例情况下 - 您最容易在参数值中简单地测试 None 并在必要时替换它。

您可以编写一个装饰器来处理一般情况,它将使用检查工具箱来计算具有默认值的参数列表中的参数值,如果它们是None,则替换它们。

下面的代码通过一些简单的测试用例演示了这个想法 - 这将起作用,但仅适用于当前构成的具有简单参数的函数(不是*args, **kwargs)。可以对其进行增强以涵盖这些情况。它像往常一样安全地处理没有默认值的参数。

Python Fiddle

import inspect

def none2defaultdecorator(thisfunc):
    (specargs, _, _, defaults) = inspect.getargspec(thisfunc)

    def wrappedfunc(*instargs):        
        callargs = inspect.getcallargs(thisfunc, *instargs)

        if len(specargs) != len(callargs):
             print "Strange - different argument count in this call to those in spec"
             print specargs
             print callargs

        for i,argname in enumerate(specargs[-len(defaults):]):
            try:
                if callargs[argname] == None:
                    callargs[argname] = defaults[i]
            except KeyError:
                # no local value for this argument - it will get the default anyway
                pass

        return thisfunc(**callargs)

    return wrappedfunc

#Decorate the funtion with the "None replacer".  Comment this out to see difference
@none2defaultdecorator            
def test(binarg = True, myint = 5):
    if binarg == True:
        print "Got binarg == true"
    elif binarg == False:
        print "Got binarg == false"
    else:
        print "Didn't understand this argument - binarg == ", binarg

    print "Argument values - binarg:",binarg,"; myint:",myint

test()
test(False)
test(True)
test(None)
test(None, None)

【讨论】:

  • 非常感谢您对此的详细回答。从概念上讲,您提出的内省方法似乎正是我想要的,但我很高兴您已经清楚地说明了警告和可能在这种方法中发生的错误的模糊化。我想我会使用你的方法——尽可能多的日志输出——同时继续寻找使我工作的基础设施的逻辑更好的方法。
【解决方案2】:

我以前没有见过这种问题,所以可能有一种方法可以改进你的逻辑并省略这个功能。

但是,有一种方法可以使用模块"inspect" 对 Python 中的代码进行自省。

一个示例用法是:

>>> def a(q=5):
...  if q is None:
...   return dict(inspect.getmembers(a))['func_defaults'][0]
...  return q
...
>>> a()
5
>>> a(None)
5

这样做的问题是“func_defaults”返回一个列表,如果您有多个参数函数,这很不方便,并且作为一个整体使过程容易出错。

【讨论】:

  • 非常感谢您提出对此采取内省方法的建议。从概念上讲,我认为你是对的。可以看到J Richard Snape给了a detailed consideration这个办法。改进代码逻辑可能是最合理的方法,但在使用大型基础架构时,这通常不是一件容易的事。
【解决方案3】:

如果参数是 TrueNone,则一种方法是对 yourfunction 赋予相同的行为。

def function(arg=True):
    if arg in [True, None]:
        do_stuff()
    else:
        do_something_else()

【讨论】:

  • 非常感谢您的建议。虽然您的方法可行,但我正在寻找更通用的方法——最好是不涉及重写现有函数库以以这种方式解释参数的方法。
【解决方案4】:

可能你想修改你的function 的实现如下:

def function(argument1 = None)
    if argument1 is None:
       argument1 = True        

    return argument1

如果你想了解更多关于默认函数参数为None的信息,你可以参考我的另一个SO answer

【讨论】:

    猜你喜欢
    • 2019-02-14
    • 2018-12-03
    • 2012-08-01
    • 1970-01-01
    • 2019-07-22
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 2021-10-04
    相关资源
    最近更新 更多