7

I think many people have seen the python's function which receives default parameters. For example:

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

If we call this function using foo(), the output will append integer '3' each time after the call.

When this function is defined, a function object named 'foo' is defined in the current environment, and also the default parameter values are evaluated at this time. Every time when the function is called without a parameter, the evaluated parameter value will be changed according to the code.

My question is, where is this evaluated parameter exist? Is it in the function object or it is in the method object when calling the function? Since everything in python is a object, there must be some place to hold the name->value binding of 'a'-->evaluated parameter. Am I over-thinking this problem?

0

6 Answers 6

12

As others already said, the default values are stored in the function object.

For example, in CPython you can do this:

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

However, co_varnames may contain more than names of args so it needs further processing and these attributes might not even be there in other Python implementations. Therefore you should use the inspect module instead which takes care of all implementation details for you:

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

The ArgSpec is a named tuple so you can access all values as attributes:

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

As the documentation says, the defaults tuple always corresponds to the n last arguments from args. This gives you your mapping.

To create a dict you could do this:

>>> dict(zip(spec.args[-len(spec.defaults):], spec.defaults))
{'a': []}
>>>
Sign up to request clarification or add additional context in comments.

Comments

5

It's attached to the function object, see foo.func_defaults:

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

In case if you want to get the mapping of a onto [], you can access 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': []}

(But, apparently, the yak's version is better.)

1 Comment

Yes, but where is the mapping of a to the [] as the OP has asked?
4

It's in the function object, in the func_defaults:

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

print f.func_defaults # ([],)

f()

print f.func_defaults # ([3],)

1 Comment

Yes, but where is the mapping of a to the [] as the OP has asked?
2

It is stored in the func_defaults attribute of the function object.

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

Comments

1

I have found an interesting situation: in python 2.5.2 version, try the function 'foo()'

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

Because the objects of the function called are different:

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

In 2.7.2 version:

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

In this case, the object is the same each time calling the function:

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

Is it a problem of different versions?

1 Comment

Shouldn't happen. Make sure you're using exactly the same functions on both versions.
0

In Python 3, funcdefaults is __defaults__:

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.