[Python-ideas] Globalize lonely augmented assignment

Georg Brandl g.brandl at gmx.net
Sat Jun 12 23:08:50 CEST 2010


Am 12.06.2010 21:40, schrieb Bruce Frederiksen:
> On Sat, Jun 12, 2010 at 2:28 PM, Georg Brandl <g.brandl at gmx.net> wrote:
>> Am 12.06.2010 17:43, schrieb Bruce Frederiksen:
>>
>>> So we are considering the case where no assignment to the variable
>>> exists within the function, but there is an augmented assignment.  But
>>> in this case, if we say that the variable is a local variable, how did
>>> this local variable get a value that the augmented assignment can then
>>> use?
>>>
>>> The only way that I can think of is:
>>>
>>> def foo():
>>>     def bar():
>>>         nonlocal A
>>>         A = []
>>>     bar()
>>>     A += [2]
>>
>> (I assume you intended a global A somewhere outside of foo().)
>> With the proposed semantics, this would actually be a compilation error,
>> since there is no nonlocal binding of A that the "nonlocal" statement
>> could bring into scope.
> 
> No, I didn't intend a global A, and yes, this would be a compilation
> error under the proposed semantics.
> 
> What I meant was that the current semantics are broken.  I think that
> it could be argued that it doesn't make sense to have augmented
> assignment cause a variable to be made local; because, outside of my
> example above, execution of the augmented assignment would _always_
> produce an UnboundLocalError.  And that's because the augmented
> assignment also refers to the variable _before_ setting it.
>
> So, to be a legal program (ie, one that doesn't raise
> UnboundLocalError), there _must_ be some other assignment to the
> variable in the function.  And if so, this other assignment would
> cause the variable to be made local, and the augmented assignment is
> immaterial to this decision.

Yes, but why does that make the current semantics broken?  Is it broken
if you do this::

   def foo():
       print a
       a = 1

I would rather say it's a programming error.  (It could be argued that
the compiler should warn about it; I would be in favor of that, if it
weren't impossible to implement correctly for all cases.)

> So my challenge (to see if I'm overlooking something) is to show me a
> current Python program that only uses augmented assignment to cause a
> variable to be made local, but does not raise UnboundLocalError when
> the augmented assignment is run.  If these examples don't exist, it
> sounds like this is a bug in the current language design.
> 
>     def foo():
>         # this causes 'a' to be made local; both current and proposed.
>         a = 5
> 
>         # so 'a' here is local; both current and proposed.
>         a += 7
> 
>     def foo():
>         # without an assignment to 'a', this is currently always an error!
>         # it can only make sense if 'a' is global!
>         a += 7
> 
> If you can't do that, then this is a bug!

Yes, it is a bug -- a bug in your code.  I don't understand your reasoning
here.  Just because you can't use a construct under some circumstances, its
semantics are buggy?  Does division have a bug because you can't divide by
zero?

>>> What am I missing?
>>
>> Currently, augmented assignment has a very straightforward translation to
>> plain assignment::
>>
>>   a += b   is equivalent to
>>   a = a.__iadd__(b)
>>
>> (Not just ``a.__iadd__(b)``, as some people think at first.  That's a
>> problem, see below.)
> 
> But this can't be treated as a simple macro expansion inside the
> compiler, as that would cause the lhs to be evaluated twice.  For
> example in:
> 
>     a[fn_with_side_effects()] += b

That's true, but it's also unimportant and a special case.

>> With the proposal, it would be much more complicated and dependent on
>> the context: "... it's the same as <code>, but if the name would only
>> be made a local by augmented assignment statements, it's automatically
>> made nonlocal if there's a matching non-local binding, or global
>> otherwise."  Pretty scary.
> 
> I agree completely that anything more complicated than striking the
> augmented assignment from the list of statements that cause a variable
> to be made local is scary.  It should not depend on what global
> bindings are present at this or that time, or whether some other local
> assignment has or has not been executed prior to the augmented
> assignment.

But by "striking" the augassign from that list, you *are* making it that
complicated.  As I explained, augmented assignment *does* contain an
assignment, so some namespace must be determined where to assign.  That
gives you the complication, because assignment is always local in Python,
except if you explicitly put a global or nonlocal statement.

> The augmented assignment statement should simply not be a
> factor in the decision to make a variable local, and having it be a
> factor is a bug in the current language design as it can never lead to
> legal programs (at least before the addition of the "nonlocal"
> statement), only misbehaving ones.

Again, I can see no bug in language design just because you can't use every
construct in every context.  Nobody forces you to write functions with only
an augassign in them.

Georg

-- 
Thus spake the Lord: Thou shalt indent with four spaces. No more, no less.
Four shall be the number of spaces thou shalt indent, and the number of thy
indenting shall be four. Eight shalt thou not indent, nor either indent thou
two, excepting that thou then proceed to four. Tabs are right out.




More information about the Python-ideas mailing list