On Thu, Nov 19, 2015 at 12:41 PM, BartC <b...@freeuk.com> wrote: > On 18/11/2015 23:22, Chris Angelico wrote: >> On the contrary, it is certain always to be that exact object. > > But, not the same value that appears as the default?
Nope. Mutable objects are never guaranteed to retain the same values. That's kinda the point. > Sorry, I didn't understand any of that. Let's try a simpler example like the > OP's. There's this innocuous looking function that you are interested in > calling: > > def fn(a=[]): > # print ("Function fn called with",a) > | a.append(10) > | return a > > It appends a value to its argument and returns the result. > > It looks like at first like, if called with no argument, it will return > [10]. If you want to think of function defaults as being values, then yes. But they're not. They're objects. > But what it actually returns depends on the entire call history since the > program started executing, something you probably have no knowledge of and > no control over. So if fn has previously been called a million times with no > argument, then after this call: > > x=fn() > > x contains a list of a million tens, not one. I'd say most people would be > rather surprised by that. So if you don't want them to be surprised by that, don't use mutable default arguments and expect them to have specific values. > I suspect those same people (unless they are experts in the murky corners of > the language) would expect: > > x=fn() > > when fn specifies a default argument of [], to be the same as writing: > > x=fn([]) > > and not be dependent on fn's entire call history. Tell me, do you expect these to do the same thing? x = [] fn(x) fn(x) fn(x) # or fn([]) fn([]) fn([]) The distinction is exactly the same. If you can understand that the first one constructs a single object and uses it three times, then you should be able to understand that the function default is also constructed once and used every time. > Your solution of using: > > def fn(a=None): > > is not really satisfactory. Partly because it now utilities two mechanisms > for the default: first to get None, then some extra code to get []. But also > it's no longer obvious how the function works and what the default is. At > least, you can't tell from a glance at the start of the function that [] is > the default. This I do agree with. It's a bit clunky. It would be nice to be able to say: def fn(a=`[]`): """If a is not passed, it will be a new empty list""" and have it function the same as: def fn(*args): a = args[0] if args else [] but currently there's no mechanism for it. (The example spelling I gave is almost certainly not going to be used, due to the Tim Peters' Monitor Grit argument, but something could probably be found.) It's a sufficiently common situation that it would merit its own syntax. Want to write up a PEP? All you need is a syntax that people can get behind. ChrisA -- https://mail.python.org/mailman/listinfo/python-list