Default parameters

Carl Banks imbosol at aerojockey.invalid
Fri Dec 19 22:55:22 EST 2003


Bengt Richter wrote:
> 
> 
> On Sat, 20 Dec 2003 01:43:00 GMT, Carl Banks <imbosol at aerojockey.invalid> wrote:
> 
>>Paul Rubin wrote:
>>> 
>>> 
>>> Carl Banks <imbosol at aerojockey.invalid> writes:
>>>> Consider something like this:
>>>> 
>>>>     def func(param=((1,2),(3,4),(5,6),(7,8))):
>>>>         whatever
>>>> 
>>>> Do you really want to be building a big-ass nested tuple every time
>>>> the function is called?
>>> 
>>> Come on, the compiler can easily recognize that that list is constant.
>>
>>Yes, but that doesn't account for all expensive parameters.  What
>>about this:
>>
>>    DEFAULT_LIST = ((1,2),(3,4),(5,6),(7,8))
>>
>>    def func(param=DEFAULT_LIST):
>>        pass
>>
>>Or this:
>>
>>    import external_module
>>
>>    def func(param=external_modules.create_constant_object()):
>>        pass
>>
>>Or how about this:
>>
>>    def func(param={'1': 'A', '2': 'B', '3': 'C', '4': 'D'}):
>>        pass
>>
>>
>>The compiler couldn't optimize any of the above cases.
> 
> For the DEFAULT_LIST (tuple?) and that particular dict literal, why not?


Well, the value of DEFAULT_LIST is not known a compile time (unless, I
suppose, this happens to be in the main module or command prompt).
The literal is not a constant, so the compiler couldn't optimize this.

(Remember, the idea is that default parameters should be evaluated at
call time, which would require the compiler to put the evaluations
inside the function's pseudo-code.  The compiler could optimize default
parameters by evaluating them at compile time: but you can only do
that with constants, for obvious reasons.)


>>Well, I don't have any data, but my gut feeling is this would be
>>somewhat more than "miniscule" performance hit.  Seeing how pervasive
>>default arguments are, I'm guessing it would be a very significant
>>slowdown if default arguments had to be evaluated every call.
>>
>>But since I have no numbers, I won't say anything more about it.
>>
> Don't know if I got this right, but
> 
> [18:32] /d/Python23/Lib>egrep -c 'def .*=' *py |cut -d: -f 2|sum
> Total = 816
> [18:32] /d/Python23/Lib>egrep -c 'def ' *py |cut -d: -f 2|sum
> Total = 4454
> 
> would seem to suggest pervasive ~ 816/4453
> or a little less than 20%

Well, if you don't like the particular adjective I used, feel free to
substitute another.  This happens a lot to me in c.l.p (see Martelli).
All I'm saying is, default arguments are common in Python code, and
slowing them down is probably going to be a significant performance
hit.

(You probably underestimated a little bit anyways: some functions
don't get to the default arguments until the second line.)


> Of course that says nothing about which are typically called in hot
> loops ;-) But I think it's a bad idea as a default way of operating
> anyway. You can always program call-time evaluations
> explicitly. Maybe som syntactic sugar could be arranged, but I think
> I would rather have some sugar for the opposite instead -- i.e.,
> being able to code a block of preset locals evaluated and bound
> locally like current parameter defaults, but not being part of the
> call signature.

Well, personally, I don't see much use for non-constant default
arguments, as we have them now, wheras they would be useful if you
could get a fresh copy.  And, frankly, the default arguments feel like
they should be evaluated at call time.  Now that we have nested
scopes, there's no need for them to simulate closures.  So, from a
purely language perspective, I think they ought to be evaluated at
call time.

The only thing is, I very much doubt I'd be willing to take the
performance hit for it.


-- 
CARL BANKS                      http://www.aerojockey.com/software
"If you believe in yourself, drink your school, stay on drugs, and
don't do milk, you can get work." 
          -- Parody of Mr. T from a Robert Smigel Cartoon




More information about the Python-list mailing list