scope of optional arguments

On 14/02/2013 at 09:29, xxxxxxxx wrote:

Hi,

I have got a stupid question I guess. It is actually not really c4d related, but I am asking here
anyway. I have got a quite simple node token class. It basically just stores instances of its own 
type.

class rhTreeToken(object) :
	def __init__(self, tokentype, children = None, subtype = None, value = None) :
		if children == None:
			self.Children = []
		else:
			self.Children   = children
		self.Subtype    = subtype
		self.Type       = tokentype
		self.Value      = value
	...

When I write the same fragment this way,

class rhTreeToken(object) :
	def __init__(self, tokentype, children = [], subtype = None, value = None) :
  
or
	def __init__(self, tokentype, children = list(), subtype = None, value = None) :
	...

my whole node structure virtually explodes. I get an infinite recursion, data from other nodes
appear as children of nodes they were never assigned to, the whole class seems to share the 
memory for rhTreeToken.Children then.

I suspect the optional arguments are not actually attached to the specific class  instance, but 
stored somewhere in Pyhton, so that the empty list would be shared by all instances.  But i could 
not find any proof / explanation for that, is that correct ?

thanks for reading,

a pretty confused,
ferdinand

On 14/02/2013 at 09:44, xxxxxxxx wrote:

Hi Ferdinand,

the behavior is correct and is not actually related to the scope. The default-value for an argument
is not created every-time the function is called, it is stored by reference.

def magic(v, l=[]) :
    l.append(v)
    print "l:", l
  
magic(0)
magic(1)
magic(2)
magic(3)

You can also look-up the default-values for a function:

print magic.func_defaults

Or even change:

magic(0)
magic(1)
magic.func_defaults = ([],)
magic(2)
magic(3)

You either have to keep with the None default-value, or copy the list for assignment.

       self.children = children[:]

-Niklas

On 14/02/2013 at 09:57, xxxxxxxx wrote:

hey thanks for the quick, answer.

i did not knew that you could do this [:] . Just to be sure that i fully understand this -
[:] is the list from start to end ?

On 14/02/2013 at 09:57, xxxxxxxx wrote:

Hi Ferdinand,

exactly, the list from start to end => copy of the list. :)

You can also use the copy module if you find it more obvious. This also has the
advantage, that it will be supported by more sequence-types than tuples or
lists.

import copy
list_1 = ["foo", "bar"]
list_2 = copy.copy(l_1)
print list_1 == list_2 # True
print list_1 is list_2 # False

-Niklas

On 14/02/2013 at 10:14, xxxxxxxx wrote:

no,  i like it, it is short, it is crpytic, chances are good, that i cannot my own code
in two weeks from now. it is perfect :)