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 :)


Log in to reply