Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > newbie question on Python tutorial example in section 4.7.1 (default arg values)

Reply
Thread Tools

newbie question on Python tutorial example in section 4.7.1 (default arg values)

 
 
Porky Pig Jr
Guest
Posts: n/a
 
      05-01-2004
Hello,
hope someone can clarify this section for me (or may be there is a
'newbie FAQs' in which case I would appreciate the link

Anyway, the example is

def f(a, L=[]):
L.append(a)
return L

and somehow L just keeps growing between the calls, so

print f(1)
returns [1]
and then
print f(2)
returns [1, 2]
etc. I'm not really clear on this example, but assume that L is set
aside somewhere (in the function definition), initialized only once
(during the def), and then all subsequent calls affect that locally
defined L.

Given this is how it works (?), I still don't understand how the
following workaround works:

def f(a, L=None):
if L is None:
L = []
L.append(a)
return L

well, it does work, but why? Seems like we initialize L to None (which
is as I undersatnd, sort of equivalent of C void), in fact it also
works if we initialize L to some arbitrary string. What I don't
understand: we check if
L is None, and then make it a list and append 'a' to it. So it becomes
a list. When then on the subsequent call it is None again rather than
list with a single value of 'a' (in the previous call)?

TIA
 
Reply With Quote
 
 
 
 
Dennis Lee Bieber
Guest
Posts: n/a
 
      05-01-2004
On 1 May 2004 14:37:44 -0700, (Porky Pig Jr)
declaimed the following in comp.lang.python:


> well, it does work, but why? Seems like we initialize L to None (which
> is as I undersatnd, sort of equivalent of C void), in fact it also


"void" is a data /type/ (normally applied to pointers, or to
places where we wish to declare that there is no return from a
function).

None is closer to C's null; technically a value that is not any
type of value.

> works if we initialize L to some arbitrary string. What I don't
> understand: we check if
> L is None, and then make it a list and append 'a' to it. So it becomes
> a list. When then on the subsequent call it is None again rather than
> list with a single value of 'a' (in the previous call)?


The L=None in the argument list is "created" when the
interpreter processes the def statement, not during later calls.

L=[] does not change the space created for the "None" during the
def, it creates a new space -- an empty array -- and attaches the label
L to that new space. The next time you call, if no second argument is
supplied, L is reattached to the None space.

Python is sort of backwards compared to most traditional
languages. In most languages, a label/variable "L" is associated with a
"box" (memory address), and assignment to "L" changes the contents of
the box. Python's labels are "post-it notes", assignment to "L" works by
moving the post-it label to where-ever the data is located, not by
moving the data to where L is located.

--
> ================================================== ============ <
> | Wulfraed Dennis Lee Bieber KD6MOG <
> | Bestiaria Support Staff <
> ================================================== ============ <
> Home Page: <http://www.dm.net/~wulfraed/> <
> Overflow Page: <http://wlfraed.home.netcom.com/> <

 
Reply With Quote
 
 
 
 
Piet
Guest
Posts: n/a
 
      05-02-2004
(Porky Pig Jr) wrote in message news:<. com>...
Hi TIA,
> def f(a, L=[]):
> L.append(a)
> return L
>
> and somehow L just keeps growing between the calls, so
>
> print f(1)
> returns [1]
> and then
> print f(2)
> returns [1, 2]
> etc. I'm not really clear on this example, but assume that L is set
> aside somewhere (in the function definition), initialized only once
> (during the def), and then all subsequent calls affect that locally
> defined L.

I agree that this one is diffcult to get. The point is (or seems to
be) that when you do not provide a value for the second argument
(which is true for all the function calls), the default value is used.
So during the first call, the interpreter notices that L is lacking,
assigns the default value to it (empty list) and then passes this
parameter together with the already given 'a' to the function.
When you call the function a second time without a value for L, the
default L will again be passed to the function, but it will not be
evaluated, so the assignment "L = []" will not be executed and the
non-empty list L will be passed to the function.
When you change the function to
> def f(a, L=None):
> if L is None:
> L = []
> L.append(a)
> return L

your first function will evaluate the assignment for L resulting in
the "value" "None" for L (I am not sure whether one should talk about
values in this context). On successive calls to the function without a
given parameter for L, the expression for L will NOT be evaluated, but
the lack of the parameter will be noted, and thus the if-clause will
be evaluated as true and assign the value "[]" to L which will then be
used on further execution.
This is at least what I thought. I just checked the behaviour of the
function when you change the default value for L from "None" to "[]".
In this case I had expected that successive calls of the function
would notice the absence of L and that the if-clause would evaluate as
true as well, but this is not the case. So when you change the
function to
> def f(a, L=[]):
> if L is None:
> L = []
> L.append(a)
> return L

and write
f(1),f(2) and so on you will also see that the list is growing with
each function call.
So my post was not that helpful, I guess. Maybe a python expert has
some explanation. I am looking forward to see how that thread will
develop.
Best wishes
Piet
 
Reply With Quote
 
Rich Krauter
Guest
Posts: n/a
 
      05-02-2004
On Sat, 2004-05-01 at 17:37, Porky Pig Jr wrote:
> Hello,
> hope someone can clarify this section for me (or may be there is a
> 'newbie FAQs' in which case I would appreciate the link
>
> Anyway, the example is
>
> def f(a, L=[]):
> L.append(a)
> return L
>
> and somehow L just keeps growing between the calls, so
>
> print f(1)
> returns [1]
> and then
> print f(2)
> returns [1, 2]
> etc. I'm not really clear on this example, but assume that L is set
> aside somewhere (in the function definition), initialized only once
> (during the def), and then all subsequent calls affect that locally
> defined L.
>
> Given this is how it works (?), I still don't understand how the
> following workaround works:
>
> def f(a, L=None):
> if L is None:
> L = []
> L.append(a)
> return L
>
> well, it does work, but why? Seems like we initialize L to None (which
> is as I undersatnd, sort of equivalent of C void), in fact it also
> works if we initialize L to some arbitrary string. What I don't
> understand: we check if
> L is None, and then make it a list and append 'a' to it. So it becomes
> a list. When then on the subsequent call it is None again rather than
> list with a single value of 'a' (in the previous call)?
>
> TIA



Not sure if this will help you, and my description may not be entirely
accurate, but it helps me to remember that a function is a an object
with attributes. One of the attributes of a function object is called
func_defaults, which contains, suprisingly enough, a tuple of function
defaults:

(as you said, "L is set aside somewhere")

>>> def func(a,L=[]):

L.append(a)
print L


>>> dir(func)

['__call__', '__class__', '__delattr__', '__dict__', '__doc__',
'__get__', '__getattribute__', '__hash__', '__init__', '__module__',
'__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__str__', 'func_closure', 'func_code', 'func_defaults',
'func_dict', 'func_doc', 'func_globals', 'func_name']

>>> func.func_defaults

([],)
>>> func(1)

[1]
>>> func.func_defaults

([1],)
>>> func(2)

[1, 2]
>>> func(3)

[1, 2, 3]
>>> func.func_defaults

([1, 2, 3],)

This happens because L (the list at func.fun_defaults[0]) is mutable.
Every call to func appends a value to that list in its func_defaults
tuple.

If L is instead made immutable in the function def, you see different
behavior:

>>> def func2(a,L=None):

if L is None:
# rebind [] to the name L, but not
# to func2.func_defaults[0]
L = []
L.append(a)
print L


>>> func2(1)

[1]
>>> func2.func_defaults

(None,)
>>> func2(2)

[2]
>>> func2.func_defaults

(None,)
>>> func2(3,L=[1,2,3])

# rebind [1,2,3] to the name L, but not to func2.func_defaults[0]
[1, 2, 3, 3]
>>> func2.func_defaults

(None,)

Hope that helps.

Rich

 
Reply With Quote
 
Scott David Daniels
Guest
Posts: n/a
 
      05-02-2004
Rich Krauter wrote:

> On Sat, 2004-05-01 at 17:37, Porky Pig Jr wrote:
>>Anyway, the example is
>>def f(a, L=[]):
>> L.append(a)
>> return L
>>
>>I still don't understand how the following workaround works:
>>
>>def f(a, L=None):
>> if L is None:
>> L = []
>> L.append(a)
>> return L
>>
>>well, it does work, but why? Seems like we initialize L to None

Here is the conceptual flaw: We initialize f's default to None.
When we call f (with only a value for a), on entry to the function
we associate the name L with the default (None). When the L = []
line is executed, we re-associate L with a new empty list.

In the original definition, we set the default to a particular new
empty list. The default will remain that particular list. L is a
name that is associated with objects, not a place a value is stored.

Mr. Pig, hopefully either my explanation or Mr. Krauter's (which is
also correct) will help you figure this out. The difference between
the two is our guess at what you don't understand. If it still does
not make sense, ask again.

An interesting exercise to show the bit about objects:

a = []
b = []
print id(a), a, id(b), b
a.append(1)
print id(a), a, id(b), b
a = b
print id(a), a, id(b), b
a.append(1)
print id(a), a, id(b), b

If you can explain the output of the four print statements and are
still confused, my explanation is not on point.

-Scott David Daniels

 
Reply With Quote
 
Porky Pig Jr
Guest
Posts: n/a
 
      05-03-2004
Scott David Daniels <> wrote in message
> If you can explain the output of the four print statements and are
> still confused, my explanation is not on point.
>
> -Scott David Daniels
>



Thanks for all the feedback, I'll study this (and other) example.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
section with in a section config file and reading that config file kampy Python 9 10-19-2012 10:59 PM
How to pass a multiline arg to exec('some.exe arg')? n00m Python 5 05-05-2008 02:58 PM
Tutorial or Example (or Tutorial) of Using Canvas to Produce a Plot W. Watson Python 13 09-20-2007 04:29 PM
Trouble with setTimeout(arg, arg) nat.hourt@gmail.com Javascript 7 11-12-2005 05:13 PM
Generators: section 9.10 of the python tutorial David Stockwell Python 3 05-13-2004 07:38 PM



Advertisments