> My slight preference for leaving += and friends alone is that > a function using them to rebind nonlocals would be hard to > read, that since the change only applies when the LHS is a > bare name the important use cases for augmented assignment > don't apply any way, that it's a bit subtle to explain that > foo.bar += baz > ( += on a dotted name) implies a plain assignment (setattr) > on foo.bar while > foo_bar += baz > ( += on bare name) might imply a := assignment (rebinding > a nonlocal) IF there are no "foo_bar = baz" elsewhere in the > same function BUT it would imply a plain assignment if there > ARE other plain assignments to the same name in the same > function, ... I think you're making this sound more complicated than it is. I don't think you'll ever *have* to explain this anyway, as long as := and += use the same rules to find their target (I'd even accept rejecting the case where the target is a global for which the compiler can't find a single assignment, breaking an utterly minuscule amount of bad code, if any). I'm *not* saying that I like := (so far I still like 'global x in f' better) but I think that either way of allowing rebinding nonlocals will also have to allow rebinding them through += and friends. I think the main weakness (for me) of := and other approaches that try to force you to say you're rebinding a nonlocal each time you do it is beginning to show: there are already well-established rules for deciding whether a bare name is local or not, and those rules have always worked "at a distance". The main reason for disallowing rebinding nonlocals in the past has been that one of those rules was "if there's a bare-name assignment to it it must be local (unless there's also a global statement for it)" (and I couldn't find a satisfactory way to add a nonlocal declarative statement and I didn't think it was a huge miss -- actually I still think it's not a *huge* miss). > IOW it seems to me that we're getting into substantial amounts > of subtlety in explaining (and thus maybe in implementing) a > functionality change that's not terribly useful anyway and may > damage rather than improve readability when it's used. > > Taking the typical P. Graham accumulator example, say: > > with += rebinding, we can code this: > > def accumulator(n=0): > def increment(i): > n += i > return n > return increment > > but without it, we would code: > > def accumulator(n=0): > def increment(i): > n := n + i > return n > return increment > > and it doesn't seem to me that the two extra keystrokes are to > be considered a substantial price to pay. That's the argument that has always been used against += by people who don't like it. The counterargument is that (a) the savings in typing isn't always that small, and (b) += *expresses the programmer's thought better*. Personally I expect that as soon as nonlocal rebinding is supported in any way, people would be hugely surprised if += and friends were not. > Admittedly in such a > tiny example readability is just as good either way, as it's obvious > which n we're talking about (there being just one, and extremely > nearby wrt the point of use of either += or := ). > > Suppose we wanted to have the accumulator "saturate" -- if > the last value it returned was > m it must restart accumulating > from zero. Now, without augmented assignment: > > def accumulator_saturating(n=0, m=100): > def increment(i): > if n > m: > n := i > else: > n := n + i > return n > return increment > > we have a pleasing symmetry and no risk of errors -- if we > mistakenly use an = instead of := in either branch the compiler > will be able to let us know immediately. (Actually I'd be quite > tempted to code the if branch as "n := 0 + i" to underscore the > symmetry, but maybe I'm just weird:-). > > If we do rely on augmented assignment being "rebinding": > > def accumulator_saturating(n=0, m=100): > def increment(i): > if n > m: > n = i > else: > n += i > return n > return increment > > the error becomes a runtime rather than compile-time one, > and does take a (small but non-zero) time to discover it. Hah. Another argument *against* rebinding by :=, and *for* a nonlocal declaration. With 'nonlocal n, m' in increment() (or however it's spelled :-) the intent is clear. > The > += 's subtle new semantics (rebinds either a local or nonlocal, > depending on how other assignments elsewhere in the > function are coded) do make it slightly harder to understand > and explain, compared to my favourite approach, which is: > := is the ONLY way to rebind a nonlocal name > (and only ever does that, only with a bare name on LHS, > etc, etc) > which can't be beaten in terms of how simple it is to understand > and explain. The compiler could then diagnose an error when it > sees := and += used on the same barename in the same > function (and perhaps give a clear error message suggesting > non-augmented := usage in lieu of the augmented assignment). > > > Can somebody please show a compelling use case for some > "nonlocal += expr" over "nonlocal := nonlocal + expr" , sufficient > to override all the "simplicity" arguments above? I guess there > must be some, since popular feeling appears to be in favour of > having augmented-assignment as "rebinding", but I can't see them. --Guido van Rossum (home page: http://www.python.org/~guido/)
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4