[Python-ideas] Tweaking closures and lexical scoping to include the function being defined

Terry Reedy tjreedy at udel.edu
Wed Sep 28 06:12:26 CEST 2011


On 9/27/2011 9:26 PM, Ethan Furman wrote:
> Terry Reedy wrote:
>> On 9/27/2011 6:32 PM, Guido van Rossum wrote:
>>> On Tue, Sep 27, 2011 at 3:24 PM, Arnaud
>>> Delobelle<arnodel at gmail.com> wrote:
>>
>>>> I may be unduly worrying about this, but it feels to me that it
>>>> lessens the overall tidiness of the language. I would much rather
>>>> there was a way to initialise these "own" variables outside the body
>>>> of the function.
>>>
>>> Yes, you have a point. Hiding side effects this way could be nasty,
>>> and this is actually the first point in favor of the default argument
>>> hack I've heard in a while. :-)
>>
>> I have several times written on python-list that Python has a simple
>> rule: header expressions (for default args) are evaluated one-time
>> when the function is defined; body expressions are evaluated (perhaps)
>> each time when the function is called. If people understand this and
>> do not fight it, they are not surprised that mutating a once-defined
>> default arg mutates it, nor that defining a function inside a loop
>> magically causes define-time binding of names in the body.
>>
>> I would hate for Python to lose this simplicity. I consider it one of
>> its positive features.
>
> Simplicity is good.
>
> I don't remember who first suggested it, and I don't remember any
> discussion on it, but what if decorator functions grew a __prepare__
> method similar to metaclasses?

At least three people, including Guido, have noted than a keyword-only 
_private parameter solves most of the problems with using default args 
for constants. Since the _underscore convention is already partly built 
into the language (import *, help(module), __mangling, __reserved__), we 
can have other tools like signature introspection also respect the 
convention.

This solution *also* works for the semi-private accumulator parameter of 
most tail-recursive functions.

Example: sum the values in a linked list (without iterators or explicit 
loops*:

def llsum(ll, *, _total = 0):
   if ll:
     return llsum(ll[1], _total = _total + ll[0])
   else:
     return _total

The private parameter _total is constant for outside calls but gets a 
new value with each recursive call. It should not appear in the public 
signature but is used internally. The non-parameter constants proposed 
as a substitute for default args would not work for this case.

* I am QUITE aware that this can be rewritten with while, and indeed I 
write the two if branches in the order I do to make it easy.

def llsum(ll)
   total = 0):
   while ll:
     ll, total = ll[1], total + ll[0]
   else:
     return total

But this is a different issue.

-- 
Terry Jan Reedy




More information about the Python-ideas mailing list