[Python-ideas] Globalize lonely augmented assignment
Nick Coghlan
ncoghlan at gmail.com
Sat Jun 12 10:12:52 CEST 2010
On 12/06/10 11:18, Demur Rumed wrote:
> I believe it would be simpler to learn that variables are _only_ local
> if bound with the assignment operator. I view the augmented assignment
> operators as different beasts. This patch doesn't quite meet its goals
> in that respect. I'd like to further the locality of a variable to "A
> variable is local if, and only if, it is first referenced as the left
> hand side of an assignment on all code paths." This patch fails to set
> that rule
The only thing even *remotely* on the table here is to take augmented
assignment out of the list of statements that will create a new local
variable.
For 3.x, that list is currently:
- assignment (i.e. '=')
- augmented assignment (i.e. '+=', '*=', etc)
- function/generator definitions (i.e. def)*
- class definitions
- for loops
- try/except statements
- import statements
- with statements
*Unlike other statements in this list, def statements can affect two
different scopes. The defined name becomes a local in the scope
containing the statement, while the names of any declared parameters
become local inside the statement's own scope.
The compiler identifies local variables via static analysis of the
function as a whole to see if they are used as name binding targets in
any of the above statements *anywhere* in the function. We are *not*
going to change that, not just because doing anything else would be far
to error-prone, but also because any other interpretation would make
compilation far too difficult.
For example, consider the following example:
def f(x):
if randint(2):
a = [5]
return a[x] # Emit code for global or local lookup?
The compiler has to choose to emit a global or local lookup opcode at
compile time - it doesn't have the luxury of knowing whether or not the
name binding statement will actually be executed at runtime, so it
ignores any conditional execution when deciding whether or not a name is
bound locally. UnboundLocalError then covers all cases where you attempt
to use a local variable name before you have bound it to something.
Now, as to the reason we can even consider taking augmented assignment
out of the list above: of the current name binding statements, it is the
*only* one which requires that a referenced name already be bound using
one of the *other* statements in the list.
If augmented assignment is currently used in a function *without*
raising UnboundLocalError at runtime, then that can only be because the
target has been bound by other means, either in the current scope, or
else in a different scope and then explicitly declared as coming from
another scope via a global or nonlocal statement.
So, without breaking existing code (that wasn't already broken), we
could change the default scope for augmented assignment from "always use
the local scope" to be:
- if a name is declared local by other means, treat it is local
- it the name exists in a surrounding scope, treat it as nonlocal
- otherwise treat it as global
That would almost certainly be more useful than the current behaviour.
The question is whether it is *sufficiently* useful to justify the
effort in updating the documentation and implementing this not just for
CPython, but for other VMs such as Jython, IronPython and PyPy.
Cheers,
Nick.
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
---------------------------------------------------------------
More information about the Python-ideas
mailing list