What is a function parameter =[] for?

Steven D'Aprano steve at pearwood.info
Thu Nov 19 07:45:41 EST 2015


On Thu, 19 Nov 2015 10:41 pm, BartC wrote:


> I expect the version with the default argument to be
> exactly the same as the last lot of calls, namely for:
> 
> fn()
> fn()
> fn()
> 
> to be equivalent to:
> 
> temp=[]
> fn(temp)
> temp=[]
> fn(temp)
> temp=[]
> fn(temp)

Why on earth would you expect that?

I don't mean that it isn't sometimes useful. Of course it is sometimes
useful, there's no doubt about that. But why would you expect the language
to default to the *slow*, *expensive*, *complicated* behaviour instead of
the *fast*, *cheap*, *simple* behaviour?

You already have one way to set the argument to a fresh list every time you
call the function: put the code you want executed inside the body of the
function. There's no need for a *second* way to get the same result.

But if you want the default value to be evaluated exactly once, and once
only, there is no real alternative to early binding. You could use a global
variable, of course, but that is no solution -- that's a problem waiting to
happen.

To get late binding, the interpreter needs to record the default expression
*and its scope* in some sort of executable code. The traditional name for
that is stolen from Algol, "thunk". And you need to decide whether it will
behave like a closure or not.

It needs to work sensibly with code like this:


i = j = k = -1
def demo():
    array = []
    for i in range(5):
        def factory():
            j = i
            def f(x=i + i**2, y=3*j+1, z=k**2 - k):
                return ((x, y, z), (i, j, k))
            return f
        array.append(factory())
    return array

func = demo()[1]
i = j = k = 9999
print(func())


>> 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.
> 
> As I said, it's bizarre. It means that for certain types, Python doesn't
> have a default that works per call, but only a default that works once
> per program.

Nonsense. The semantics of default values is *completely* independent of the
type. Python ALWAYS uses early binding, regardless of the type. Whether the
default is an int, None, a list, a dict, a float, or some other instance,
the behaviour is the same: the default value is the specific instance which
the default expression evaluates to when the function is created.


-- 
Steven




More information about the Python-list mailing list