[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