Am 12.06.2010 21:40, schrieb Bruce Frederiksen:
On Sat, Jun 12, 2010 at 2:28 PM, Georg Brandl
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.