Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Empty list as default parameter

Reply
Thread Tools

Empty list as default parameter

 
 
Alex Panayotopoulos
Guest
Posts: n/a
 
      11-21-2003
Hello all,

Maybe I'm being foolish, but I just don't understand why the following
code behaves as it does:

- = - = - = -

class listHolder:
def __init__( self, myList=[] ):
self.myList = myList

def __repr__( self ): return str( self.myList )

# debug: 'a' should contain 42, 'b' should be empty. But no.
a = listHolder()
a.myList.append( 42 )
b = listHolder()
print a
print b

- = - = - = -

I was expecting to see [42] then [], but instead I see [42] then [42]. It
seems that a and b share a reference to the same list object. Why?

--
<<<Alexspudros Potatopoulos>>>
Defender of Spudkind

 
Reply With Quote
 
 
 
 
Fredrik Lundh
Guest
Posts: n/a
 
      11-21-2003
Alex Panayotopoulos wrote:

> Maybe I'm being foolish, but I just don't understand why the following
> code behaves as it does:
>
> - = - = - = -
>
> class listHolder:
> def __init__( self, myList=[] ):
> self.myList = myList
>
> def __repr__( self ): return str( self.myList )
>
> # debug: 'a' should contain 42, 'b' should be empty. But no.
> a = listHolder()
> a.myList.append( 42 )
> b = listHolder()
> print a
> print b
>
> - = - = - = -
>
> I was expecting to see [42] then [], but instead I see [42] then [42]. It
> seems that a and b share a reference to the same list object. Why?


the default value expression is evaluated once, when the function
object is created, and the resulting object is bound to the argument.

if you want to create a new object on every call, you have to do
that yourself:

def __init__( self, myList=None):
if myList is None:
myList = [] # create a new list
self.myList = myList

or perhaps:

def __init__( self, myList=None):
self.myList = myList or []

see the description of the "def" statement for more info:

http://www.python.org/doc/current/ref/function.html

</F>




 
Reply With Quote
 
 
 
 
Thorsten Pferdekämper
Guest
Posts: n/a
 
      11-21-2003
>
> class listHolder:
> def __init__( self, myList=[] ):
> self.myList = myList
>
> def __repr__( self ): return str( self.myList )
>
> # debug: 'a' should contain 42, 'b' should be empty. But no.
> a = listHolder()
> a.myList.append( 42 )
> b = listHolder()
> print a
> print b
>
> - = - = - = -
>
> I was expecting to see [42] then [], but instead I see [42] then [42]. It
> seems that a and b share a reference to the same list object. Why?
>


Hi,
AFAIK, the default parameter values are only instantiated once. So, the
default-myList is always the same object. The coding above should be
rewritten like...

class listHolder:
def __init__( self, myList=None ):
if myList = None:
self.myList = []
else:
self.myList = myList

Regards,
Thorsten




 
Reply With Quote
 
anton muhin
Guest
Posts: n/a
 
      11-21-2003
Alex Panayotopoulos wrote:

> Hello all,
>
> Maybe I'm being foolish, but I just don't understand why the following
> code behaves as it does:
>
> - = - = - = -
>
> class listHolder:
> def __init__( self, myList=[] ):
> self.myList = myList
>
> def __repr__( self ): return str( self.myList )
>
> # debug: 'a' should contain 42, 'b' should be empty. But no.
> a = listHolder()
> a.myList.append( 42 )
> b = listHolder()
> print a
> print b
>
> - = - = - = -
>
> I was expecting to see [42] then [], but instead I see [42] then [42]. It
> seems that a and b share a reference to the same list object. Why?
>


Really common mistake: lists are _mutable_ objects and self.myList
references the same object as the default parameter. Therefore
a.myList.append modifies default value as well. Mutable defaults are
better avoided (except for some variants of memo pattern). Standard
trick is:

def __init__(self, myList = None):
if myList is None:
self.myList = []
else:
self.myList = myList

regards,
anton.

 
Reply With Quote
 
Alex Panayotopoulos
Guest
Posts: n/a
 
      11-21-2003
On Fri, 21 Nov 2003, anton muhin wrote:

> Really common mistake: lists are _mutable_ objects and self.myList
> references the same object as the default parameter. Therefore
> a.myList.append modifies default value as well.


It does?!
Ah, I've found it: listHolder.__init__.func_defaults

Hmm... this behaviour is *very* counter-intuitive. I expect that if I were
to define a default to an explicit object...

def process_tree1( start=rootNode )

....then I should indeed be able to process rootNode through manipulating
start. However, if I define a default as a new instance of an object...

def process_tree2( myTree=tree() )

....then the function should, IMHO, create a new object every time it is
entered. (By having func_defaults point to tree.__init__, or summat.)

Was there any reason that this sort of behaviour was not implemented?

> Mutable defaults are better avoided (except for some variants of memo
> pattern). Standard trick is:
>
> def __init__(self, myList = None):
> if myList is None:
> self.myList = []
> else:
> self.myList = myList


Thank you. I shall use this in my code. (Although I would have preferred a
trick that uses less lines!)

--
<<<Alexspudros Potatopoulos>>>
Defender of Spudkind

 
Reply With Quote
 
anton muhin
Guest
Posts: n/a
 
      11-21-2003
Alex Panayotopoulos wrote:

> On Fri, 21 Nov 2003, anton muhin wrote:
>
>
> Was there any reason that this sort of behaviour was not implemented?
>
>

It was discussed several times (search for it, if you're interested),
but I don't remeber details.

>>Mutable defaults are better avoided (except for some variants of memo
>>pattern). Standard trick is:
>>
>> def __init__(self, myList = None):
>> if myList is None:
>> self.myList = []
>> else:
>> self.myList = myList

>
>
> Thank you. I shall use this in my code. (Although I would have preferred a
> trick that uses less lines!)
>


if you wish a one-linear, somehting like this might work:
self.myList = myList or []

regards,
anton.

 
Reply With Quote
 
Andrei
Guest
Posts: n/a
 
      11-21-2003
Alex Panayotopoulos wrote on Fri, 21 Nov 2003 13:26:13 +0000:

<snip>
> Hmm... this behaviour is *very* counter-intuitive. I expect that if I were
> to define a default to an explicit object...


I think so too. It's documented as a Python pitfall. Here are some more:
http://zephyrfalcon.org/labs/python_pitfalls.html

>> def __init__(self, myList = None):
>> if myList is None:
>> self.myList = []
>> else:
>> self.myList = myList

>
> Thank you. I shall use this in my code. (Although I would have preferred a
> trick that uses less lines!)


You could use the quasi-ternary trick:

>>> mylist = None
>>> (mylist is None and [[]] or [mylist])[0]

[]
>>> mylist = []
>>> (mylist is None and [[]] or [mylist])[0]

[]
>>> mylist = [3,4]
>>> (mylist is None and [[]] or [mylist])[0]

[3, 4]

Not that big an improvement really .

--
Yours,

Andrei

=====
Mail address in header catches spam. Real contact info (decode with rot13):
http://www.velocityreviews.com/forums/(E-Mail Removed). Fcnz-serr! Cyrnfr qb abg hfr va choyvp cbfgf. V ernq
gur yvfg, fb gurer'f ab arrq gb PP.


 
Reply With Quote
 
Robin Munn
Guest
Posts: n/a
 
      11-21-2003
Alex Panayotopoulos <(E-Mail Removed)> wrote:
> On Fri, 21 Nov 2003, anton muhin wrote:
>
>> Really common mistake: lists are _mutable_ objects and self.myList
>> references the same object as the default parameter. Therefore
>> a.myList.append modifies default value as well.

>
> It does?!
> Ah, I've found it: listHolder.__init__.func_defaults
>
> Hmm... this behaviour is *very* counter-intuitive. I expect that if I were
> to define a default to an explicit object...
>
> def process_tree1( start=rootNode )
>
> ...then I should indeed be able to process rootNode through manipulating
> start. However, if I define a default as a new instance of an object...
>
> def process_tree2( myTree=tree() )
>
> ...then the function should, IMHO, create a new object every time it is
> entered. (By having func_defaults point to tree.__init__, or summat.)
>
> Was there any reason that this sort of behaviour was not implemented?


The reason for this behavior lies in the fact that Python is an
interpreted language, and that the class and def keywords are actually
considered statements. One creates a class object with a certain name,
the other creates a function object with a certain name. The def (or
class) statement is executed as soon as the entire function code or
class code has been parsed -- in other words, as soon as the interpreter
drops out of the indentation block of the def or class statement.
Therefore, any default values passed to function arguments in a def
statement will be evaluated once and only once, when the def statement
is executed.

Look at this, for example:


n = 5
def f(x = n):
return x
n = 3

print n # Prints 3
print f() # Prints 5

Note that the default argument to f() is the value of n when the def
statement was executed, not the value of n when f() is called.

--
Robin Munn
(E-Mail Removed)
 
Reply With Quote
 
Dennis Lee Bieber
Guest
Posts: n/a
 
      11-21-2003
Alex Panayotopoulos fed this fish to the penguins on Friday 21 November
2003 05:26 am:


>
> Was there any reason that this sort of behaviour was not implemented?
>

Because, to be simplistic, the def statement is not a declaration, it
is an executable statement. Execution of def results in the generation
of a function object, which requires evaluating argument definitions.
Execution of def occurs /once/, during the initial load of the
module/file.

This is much different from things like old BASICs, where calling a
function causes the interpreter to rescan the source file to find the
function declaration.

Others can explain it much better.

--
> ================================================== ============ <
> (E-Mail Removed) | Wulfraed Dennis Lee Bieber KD6MOG <
> (E-Mail Removed) | Bestiaria Support Staff <
> ================================================== ============ <
> Bestiaria Home Page: http://www.beastie.dm.net/ <
> Home Page: http://www.dm.net/~wulfraed/ <


 
Reply With Quote
 
Peter Otten
Guest
Posts: n/a
 
      11-21-2003
anton muhin wrote:

> Alex Panayotopoulos wrote:
>
>> On Fri, 21 Nov 2003, anton muhin wrote:
>>
>>
>> Was there any reason that this sort of behaviour was not implemented?
>>
>>

> It was discussed several times (search for it, if you're interested),
> but I don't remeber details.
>
>>>Mutable defaults are better avoided (except for some variants of memo
>>>pattern). Standard trick is:
>>>
>>> def __init__(self, myList = None):
>>> if myList is None:
>>> self.myList = []
>>> else:
>>> self.myList = myList

>>
>>
>> Thank you. I shall use this in my code. (Although I would have preferred
>> a trick that uses less lines!)
>>

>
> if you wish a one-linear, somehting like this might work:
> self.myList = myList or []


This is dangerous, don't do it.

>>> None or "just a marker"

'just a marker'

seems to work. But:

>>> [] or "just a marker"

'just a marker'

I. e. your one-liner will create a new list when the myList argument is not
provided or is provided and bound to an empty list.

Peter
 
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
Empty function parameter list Maxim Fomin C Programming 7 06-15-2012 12:22 PM
behavior varied between empty string '' and empty list [] Tzury Bar Yochay Python 1 03-24-2008 06:56 PM
Using declaration inside first template parameter as default valuefor second template parameter. Stuart Redmann C++ 5 12-14-2007 08:42 AM
Parameter List / Parameter Block / Anything patterns... mast2as@yahoo.com C++ 4 03-29-2007 09:37 PM
Using default a empty dictionary as a default value C Gillespie Python 3 03-22-2005 12:22 PM



Advertisments