7

我想很多人都看过python接收默认参数的函数。例如:

def foo(a=[]):
    a.append(3)
    return a

如果我们使用 foo() 调用此函数,则每次调用后输出都会附加整数“3”。

定义此函数时,会在当前环境中定义一个名为 'foo' 的函数对象,同时也会评估默认参数值。每次在没有参数的情况下调用函数时,评估的参数值将根据代码更改。

我的问题是,这个评估参数在哪里存在? 调用函数时是在函数对象中还是在方法对象中? 由于python中的一切都是一个对象,因此必须有一些地方来保存'a'-->已评估参数的名称->值绑定。我是不是在想这个问题?

4

5 回答 5

11

正如其他人已经说过的,默认值存储在函数对象中。

例如,在 CPython 中,您可以这样做:

>>> def f(a=[]):
...     pass
...
>>> f.func_defaults
([],)
>>> f.func_code.co_varnames
('a',)
>>>

但是,co_varnames可能包含多个 args 的名称,因此它需要进一步处理,并且这些属性甚至可能在其他 Python 实现中不存在。因此,您应该使用该inspect模块来代替您处理所有实现细节:

>>> import inspect
>>> spec = inspect.getargspec(f)
>>> spec
ArgSpec(args=['a'], varargs=None, keywords=None, defaults=([],))
>>>

ArgSpec是一个命名元组,因此您可以将所有值作为属性访问:

>>> spec.args
['a']
>>> spec.defaults
([],)
>>>

正如文档所说,defaults元组始终对应于来自args. 这为您提供了映射。

要创建一个 dict 你可以这样做:

>>> dict(zip(spec.args[-len(spec.defaults):], spec.defaults))
{'a': []}
>>>
于 2012-04-12T10:03:50.130 回答
5

它附加到函数对象,请参阅foo.func_defaults

>>> foo()
>>> foo.func_defaults
([3],)
>>> foo()
>>> foo.func_defaults
([3, 3],)

如果您想获得 on 的映射a[]您可以访问foo.func_code

defaults = foo.func_defaults
# the args are locals in the beginning:
args = foo.func_code.co_varnames[:foo.func_code.co_argcount] 
def_args = args[-len(defaults):]  # the args with defaults are in the end
print dict(zip(def_args, defaults)) # {'a': []}

(但是,显然,牦牛的版本更好。)

于 2012-04-12T09:36:52.683 回答
4

它在函数对象中,在func_defaults

def f(a=[]): a.append(3)

print f.func_defaults # ([],)

f()

print f.func_defaults # ([3],)
于 2012-04-12T09:37:39.363 回答
2

它存储在func_defaults函数对象的属性中。

>>> foo.func_defaults
([],)
>>> foo()
([3],)
于 2012-04-12T09:37:44.567 回答
1

我发现了一个有趣的情况:在 python 2.5.2 版本中,尝试函数 'foo()'

>>> foo()
[1]
>>> foo()
[1]
>>> foo()
[1]

因为被调用的函数的对象不同:

>>> id(foo())
4336826757314657360
>>> id(foo())
4336826757314657008
>>> id(foo())
4336826757314683160

在 2.7.2 版本中:

>>> foo()
[1]
>>> foo()
[1, 1]
>>> foo()
[1, 1, 1]

在这种情况下,每次调用函数时对象都是相同的:

>>> id(foo())
29250192
>>> id(foo())
29250192
>>> id(foo())
29250192

是不是版本不同的问题?

于 2012-04-12T14:31:01.883 回答