
On Wed, Sep 28, 2011 at 5:41 PM, Jim Jewett <jimjjewett@gmail.com> wrote:
On Wed, Sep 28, 2011 at 12:12 AM, Terry Reedy <tjreedy@udel.edu> wrote:
... 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.
Note that this also matches indentation, since decorators are indented with the header, rather than with the body.
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.
Though they may still be surprised in the opposite direction; that you have to write an explicit and redundant i=i to capture the current value when binding.
I would hate for Python to lose this simplicity.
Agreed.
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.
Additional advantages:
(a) Because it is still a parameter, it *can* be altered for test code; it is just obvious that you're doing something unsupported.
(b) The only patch required is to documentation. Instead of saying "Don't do that", the documentation should say "If you just want to save state between calls, make it a keyword-only parameter and indicate that it is private by prefixing the name with an underscore." That is pretty hard to beat from a backwards-compatibility standpoint.
Um, but you can't save state between calls in a default argument value, except by the hack of making it a list (or some other mutable object) and mutating that. -- --Guido van Rossum (python.org/~guido)