有没有办法知道参数的值是否是默认值与用户指定的值?

时间:2012-06-28 18:54:45

标签: python arguments

我正在寻找像Lisp的arg-supplied-p变量一样的东西,以帮助区分默认值和用户指定的相同值。

示例:

def foo(a=10):
    pass

我想在foo中知道它是否被这样称呼:

foo()

或者像这样:

foo(10)

甚至是这样:

foo(a=10)

最后2个对我来说是同义词;我不需要知道那个细节。我已经仔细查看了检查模块,但getargspec为所有3个调用返回了完全相同的结果。

4 个答案:

答案 0 :(得分:11)

除了检查源代码之外,没有办法区分三个函数调用 - 它们意味着具有完全相同的含义。如果您需要区分它们,请使用其他默认值,例如None

def foo(a=None):
    if a is None:
        a = 10
        # no value for a provided

答案 1 :(得分:6)

正如Sven所指出的,通常使用None作为默认参数。如果您甚至需要区分无参数和显式无提示,则可以使用sentinel对象:

sentinel = object()

def foo(a=sentinel):
    if a is sentinel:
        # No argument was provided
        ...

答案 2 :(得分:2)

不是真的。您可以使用foo.func_defaults来获取函数的默认参数列表,这样您就可以使用它来检查传递的参数的对象标识。但这只会对可变对象可靠地起作用。在你的例子中,没有办法告诉你是否有人通过了10或使用了默认的10,因为两个10都可能是同一个对象。

这只是一个粗略的近似,因为它没有告诉你如何调用函数:它告诉你默认的参数是什么,你看看实际的参数,并试着猜测它们是否相同。无法访问用于调用函数的语法形式。

这是一个示例,显示它有时如何工作,有时不工作。

>>> def f(x="this is crazy"):
...     print x is f.func_defaults[0]
>>> f()
True
>>> f("this is crazy")
False
>>> def f(x=10):
...     print x is f.func_defaults[0]
>>> f()
True
>>> f(10)
True

答案 3 :(得分:0)

被调用的函数只获取最终的参数值,无论是默认值还是传入的东西。那么你需要做些什么来判断调用者是否传入某些东西是为了使默认值为他们无法传递的东西。

他们可以传入None,因此您无法使用它。你能用什么?

最简单的解决方案是创建某种类型的Python对象,将其用作函数中的默认值,然后del,这样用户就无法引用它。从技术上讲,用户可以从你的功能对象中挖掘出来,但是他们很少会这么做,如果他们这样做,你可以说他们应该得到他们得到的东西。

default = []

def foo(a=default):
    if a is default:
        a = 10
    print a

del default

我在这里使用的“默认值”是一个空列表。由于列表是可变的,因此它们永远不会被重用,这意味着每个空列表都是唯一的对象。 (Python实际上对所有空元组使用相同的空元组对象,因此不要使用空元组!字符串文字和小整数同样重复使用,所以不要使用它们。)object实例将是精细。任何东西,只要它是可变的,因此不被分享。

现在问题是上面的代码实际上并没有运行del default。如何在运行时在函数中获得对此对象的引用,以便可以对其进行测试?一种方法是使用默认参数值,该值不用于实际参数。

default = []

def foo(a=default, default=default):
    if a is default:
          a = 10
     print a

del default

当定义函数时,这会将对象绑定到参数的默认值,因此稍后删除全局名称并不重要。但问题是,如果有人对你的函数做help(),或者对其进行反思,那么看起来他们可以传递一个额外的参数。更好的解决方案是闭包:

default = []

def foo(default=default):   # binds default to outer func's local var default
    def foo(a=default):     # refers to outer func's local var default
        if a is default:
            a = 10
        print a
    return foo
foo = foo()

del default

这是相当多的工作,所以真的,不要打扰。