[Tutor] Re: python's default argument value handling in functions - weird syntax? problem grappling with the concept

Abel Daniel abli at freemail.hu
Wed Feb 9 23:50:49 CET 2005


quoted lines are from Jeffrey Lim
[... I have rearranged the order of the quotes ...]

> How is 'L == None' even possible all the time, given that for
> def f(a, L=[]):
>     L.append(a)
>     return L
> , L isn't even [] except for the first call to 'f'?

This is the important point. You see, its true that L != [] for those
calls, but despite this, L _is_ []. I guess this sounds wierd, so I'll
clarify it:

Lets try it with a little modification. Instead of "def f(a, L=[])",
we will use "def f(a, L=l)", where l is an empty list. This surely
shouldn't cause any difference, should it?

>>> l=[]
>>> def f(a, L=l):
...     L.append(a)
...     return L
... 
>>> f(1)
[1]
>>> f(2)
[1, 2]
>>> f(3)
[1, 2, 3]

So far, so good. Now lets see whether L is [] or not:

>>> a=f(4) # so now a is whatever L was inside the function
>>> a == l
True

and:

>>> a is l  
True

So L _is_ [], isn't it? How can this happen? After all, by now L is
[1,2,3,4], right? And l is an empty list, right? Well, wrong:

>>> l
[1, 2, 3, 4]

So the strange thing is that even though L is _not_ [] (as in, its not
an empty list) it _is_ [] in some sence. That is, it is the _same_
list which was [] once. This second sentence might sound pretty
wierd. You have to keep in mind, that every time you type [], python
will create a _new_, empty list. This means that:

>>> [] is []
False

The big difference between the "def f(a, L=[])" and "def f(a, L=None)"
cases is that in the first, L is a list, and lists are mutable. In the
second, L is None and obviously, None is not mutable. In both cases
you give an object as a default value. In both cases, L will _allways_
be this object at the first line of the function when you call the
function. The difference is that in the first case, although you can't
change the _identity_ of the default value, you can change its
_content_ . And thats what you do with the line "L.append(a)".

Keep in mind that L=[] does _not_ copy the list. In fact, in python
even a=5 does not copy anything. In C, variables might be thought of
as little drawers that have something in them. When you say a=b, the
contents of b get copied to a. In python, however, variables are
better thought of as labels. When you say a=5, you put a label on the
number 5 object. Its like saying "I want to be able to call that
number a". When doing a=b, there is no copying, what happens is that
the label 'a' gets moved to the object which has the label 'b' on it.

In the previous paragraph, I have written "when you say a=5, you put a
label on the number 5 object". Maybe I should have written "you put a
label on a number 5 object". Notice the difference? For numbers, one
could claim that there is no difference. After all, there is only one
number 5, right? However, as we have seen above, for lists, you can't
claim the same. There is no _the_ []. Every '[]' will create a new
one.

If you think of variables as labels on objects, and objects as having
content and identity, everything should become clear. ('==' compares
by value, that is, by content, 'is' compares by identity. Make sure
not to mix identity with eguality.)

Recommended reading:

http://www.effbot.org/zone/python-objects.htm (understanding python
objects, pretty short)

http://starship.python.net/crew/mwh/hacks/objectthink.html ("variables
as labels", a bit longer)



ps. For extra wierdness, in python "there is only one number 5" isn't
true for large numbers:
>>> a=100
>>> b=100
>>> a is b
False

Using a large number is important: integers up to 99 are cached, so
they _are_ unique (we would get True above). For larger numbers, the
cacheing is more subtle, for example:
>>> a, b = 100, 100
>>> a is b
True

--
Abel Daniel


More information about the Tutor mailing list