What is a function parameter =[] for?
Chris Angelico
rosuav at gmail.com
Wed Nov 18 20:59:18 EST 2015
On Thu, Nov 19, 2015 at 12:41 PM, BartC <bc at 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
More information about the Python-list
mailing list