[Victor Stinner]Let's say that the PEP 572 (assignment expression) is going to be
> approved. Let's move on and see how it can be used in the Python stdlib. > Ugh - how adult ;-) > I propose to start the discussion about "coding style" (where are > assignment expressions appropriate or not?) with the "while True" > case. > > I wrote a WIP pull request to use assignment expressions in "while True": > https://github.com/python/cpython/pull/8095/files > > In short, replace: > > while True: > x = expr > if not x: > break > ... > with: > > while (x := expr): Better is to translate it to: while x := expr: That is, ;parentheses aren't needed in this context, and adding them anyway will quickly look as strange here as, e.g., return (result) already looks. (Always requiring parens was rejected - see the PEP's "Always requiring parentheses <https://www.python.org/dev/peps/pep-0572/#id24>" section). ... > ... > == Pattern 3, double condition == > > while True: > s = self.__read(1) > if not s or s == NUL: > break > .... > > replaced with: > > while (s := self.__read(1)) and s != NUL: > ... > Honestly, here, I don't know if it's appropriate... > Then leave it be! My rule was "if it's not obviously better - at least a little - don't use it". This one is a wash (tie) to me, so I'd save the bother of changing it. Or just do the obvious part: while s := self.__read(1): if s == NUL: break No matter how the code may change in the future, the loop body surely requires a non-empty `s` to stare at. and now the `while` header makes that abundantly clear at a glance. ... > == Pattern 4, while (...): pass == > > Sometimes, the loop body is replaced by "pass". > > while True: > tarinfo = self.next() > if tarinfo is None: > break > > replaced with: > > while (tarinfo := self.next()) is not None: > pass > > It reminds me the *surprising* "while (func());" or "while (func()) > {}" in C (sorry for theorical C example, I'm talking about C loops > with an empty body). > > Maybe it's acceptable here, I'm not sure. > > Note: such loop is rare (see my PR). > I decided "slight loss - don't bother" for most such in my own code. At least the first spelling above cuts the number of statements in half. Replacing random.py's r = getrandbits(k) while r >= n: r = getrandbits(k) with while (r := getrandbits(k)) >= n: pass is more attractive, for eliminating a textually identical (except for indentation) line. == Pattern 5, two variables == > > while True: > m = match() > if not m: > break > j = m.end() > if i == j: > break > ... > > replaced with: > > while (m := match()) and (j := m.end()) == i: > ... > > Maybe we reached here the maximum acceptable complexity of a single > Python line? :-) > It's at my limit. But, as in an earlier example, I'd be tempted to do "the obvious part": while m:= match(): j = m.end() if i == j:: break Then the start reads like "while there's something _to_ look at::" and the body of the loop is happily guaranteed that there is. ... > I chose to not use assignment expressions for the following while loops. > > (A) > > while True: > name, token = _getname(g) > if not name: > break > ... > > "x, y := ..." is invalid. It can be tricked using "while (x_y :=...)[0]: > x, y = x_y; ...". IMHO it's not worth it. Indeed, it's quite worth _not_ doing it :-) > (B) > > while True: > coeff = _dlog10(c, e, places) > # assert len(str(abs(coeff)))-p >= 1 > if coeff % (5*10**(len(str(abs(coeff)))-p-1)): > break > places += 3 > > NOT replaced with: > > while not (coeff := _dlog10(c, e, places)) % > (5*10**(len(str(abs(coeff)))-p-1)): > places += 3 > > ^-- Tim Peters, I'm looking at you :-) > Not my code ;-) - and it's _already_ too "busy" to be my code. The `5*10**...` part is already crying to be broken into simpler pieces with a comment explaining what the intent is. > coeff is defined and then "immediately" used in "y" expression of > x%y... Yeah, it's valid code, but it looks too magic to me... > And the code was already too dense to follow easily. (C) > > while True: > chunk = self.raw.read() > if chunk in empty_values: > nodata_val = chunk > break > ... > > "nodata_val = chunk" cannot be put into the "chunk := self.raw.read()" > assignment expression combined with a test. At least, I don't see how. > > No need to strain, either! If it's not obvious, don't bother. > (D) > > while 1: > u1 = random() > if not 1e-7 < u1 < .9999999: > continue > ... > > Again, I don't see how to use assignment expression here. > > It could be, in context, but not for the outermost `while 1:`. while 1: while not 1e-7 < (u1 := random()) < 9999999: pass # code that uses u1, and possibly returns, else goes # around the outer loop again That one is fine by me either way. In all, I'd say our tastes here are pretty similar! So there's hope ;-)
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com