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?
Yes. The bindings of default values for call args are evaluated at define-time,
in the context of the definition, not at execution time, when the function is called.
If you want to specify what to call at execution time, you have to call it at execution time,
so you either have to pass a reference to the thing to call ('tree' in this case) or have it
otherwise visible from inside the function, e.g., the interface could be something like
def process_tree2(treemaker=tree):
myTree = treemaker()
...
Now if you wanted to pass a pre-existing tree to this kind of process_tree2, you'd have to
pass a callable that would execute to produce the tree, e.g., call it like
temp_treemaker = lambda: rootNode
process_tree2(temp_treemaker) # or just put the lambda expression right in the call
More likely, you'd want to be able to accept a tree, or make one if nothing was passed. E.g.,
def process_tree3(myTree=None):
if myTree is None: myTree = tree() # here tree must be visible in an enclosing scope
... # -- usually global, but not necessarily
a variant would be to have a default value of a single particular tree, as in your first example,
and then test whether something executable, like tree (not tree()) was being passed, e.g.,
def process_tree1( start=rootNode ):
if callable(start): start = start() # e.g., if called like process_tree1(tree)
Of course, if a node object is also callable, you have to make a different check ;-)
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!)
How about two less? I usually do it (with no trick ;-) like:
def __init__(self, myList = None):
if myList is None: myList = []
self.myList = myList
Regards,
Bengt Richter