Remove excess indentation.

This commit is contained in:
R. David Murray 2017-09-05 14:54:46 -04:00
parent 0cfa95c9e9
commit 5c1080518d
1 changed files with 192 additions and 192 deletions

View File

@ -14,260 +14,260 @@ Post-History:
Abstract Abstract
======== ========
This PEP proposes enhancing the ``break`` and ``continue`` statements This PEP proposes enhancing the ``break`` and ``continue`` statements
with an optional boolean expression that controls whether or not with an optional boolean expression that controls whether or not
they execute. This allows the flow of control in loops to be they execute. This allows the flow of control in loops to be
expressed more clearly and compactly. expressed more clearly and compactly.
Motivation Motivation
========== ==========
Quoting from the rejected :pep:`315`: Quoting from the rejected :pep:`315`:
It is often necessary for some code to be executed before each It is often necessary for some code to be executed before each
evaluation of the while loop condition. This code is often evaluation of the while loop condition. This code is often
duplicated outside the loop, as setup code that executes once duplicated outside the loop, as setup code that executes once
before entering the loop:: before entering the loop::
<setup code> <setup code>
while <condition>: while <condition>:
<loop body>
<setup code>
That PEP was rejected because no syntax was found that was superior
to the following form::
while True:
<setup code>
if not <condition>:
break
<loop body> <loop body>
<setup code>
This PEP proposes a superior form, one that also has application to That PEP was rejected because no syntax was found that was superior
for loops. It is superior because it makes the flow of control in to the following form::
loops more explicit, while preserving Python's indentation aesthetic.
while True:
<setup code>
if not <condition>:
break
<loop body>
This PEP proposes a superior form, one that also has application to
for loops. It is superior because it makes the flow of control in
loops more explicit, while preserving Python's indentation aesthetic.
Syntax Syntax
====== ======
The syntax of the break and continue statements are extended The syntax of the break and continue statements are extended
as follows:: as follows::
break_stmt : "break" ["if" expression] break_stmt : "break" ["if" expression]
continue_stmt : "continue" ["if" expression] continue_stmt : "continue" ["if" expression]
In addition, the syntax of the while statement is modified as follows:: In addition, the syntax of the while statement is modified as follows::
while_stmt : while1_stmt|while2_stmt while_stmt : while1_stmt|while2_stmt
while1_stmt : "while" expression ":" suite while1_stmt : "while" expression ":" suite
["else" ":" suite] ["else" ":" suite]
while2_stmt : "while" ":" suite while2_stmt : "while" ":" suite
Semantics Semantics
========= =========
A ``break if`` or ``continue if`` is executed if and only if A ``break if`` or ``continue if`` is executed if and only if
``expression`` evaluates to true. ``expression`` evaluates to true.
A `while` statement with no expression loops until a break or return A `while` statement with no expression loops until a break or return
is executed (or an error is raised), as if it were a `'while True`` is executed (or an error is raised), as if it were a `'while True``
statement. Given that the loop can never terminate except in a statement. Given that the loop can never terminate except in a
way that would not cause an ``else`` suite to execute, no ``else`` way that would not cause an ``else`` suite to execute, no ``else``
suite is allowed in the expressionless form. If practical, it suite is allowed in the expressionless form. If practical, it
should also be an error if the body of an expressionless ``while`` should also be an error if the body of an expressionless ``while``
does not contain at least one ``break`` or ``return`` statement. does not contain at least one ``break`` or ``return`` statement.
Justification and Examples Justification and Examples
========================== ==========================
The previous "best possible" form:: The previous "best possible" form::
while True: while True:
<setup code> <setup code>
if not <condition>: if not <condition>:
break break
<loop body> <loop body>
could be formatted as:: could be formatted as::
while True: while True:
<setup code> <setup code>
if not <condition>: break if not <condition>: break
<loop body> <loop body>
This is superficially almost identical to the form proposed by this This is superficially almost identical to the form proposed by this
PEP:: PEP::
while: while:
<setup code> <setup code>
break if not <condition> break if not <condition>
<loop body> <loop body>
The significant difference here is that the loop flow control The significant difference here is that the loop flow control
keyword appears *first* in the line of code. This makes it easier keyword appears *first* in the line of code. This makes it easier
to comprehend the flow of control in the loop at a glance, especially to comprehend the flow of control in the loop at a glance, especially
when reading colorized code. when reading colorized code.
For example, this is a common code pattern, taken in this case For example, this is a common code pattern, taken in this case
from the tarfile module:: from the tarfile module::
while True: while True:
buf = self._read(self.bufsize) buf = self._read(self.bufsize)
if not buf: if not buf:
break break
t.append(buf) t.append(buf)
Reading this, we either see the break and possibly need to think about Reading this, we either see the break and possibly need to think about
where the while is that it applies to, since the break is indented where the while is that it applies to, since the break is indented
under the if, and then track backward to read the condition that under the if, and then track backward to read the condition that
triggers it; or, we read the condition and only afterward discover triggers it; or, we read the condition and only afterward discover
that this condition changes the flow of the loop. that this condition changes the flow of the loop.
With the new syntax this becomes:: With the new syntax this becomes::
while: while:
buf = self._read(self.bufsize) buf = self._read(self.bufsize)
break if not buf break if not buf
t.append(buf) t.append(buf)
Reading this we first see the``break``, which obviously applies to Reading this we first see the``break``, which obviously applies to
the while since it is at the same level of indentation as the loop the while since it is at the same level of indentation as the loop
body, and then we read the condition that causes the flow of control body, and then we read the condition that causes the flow of control
to change. to change.
Further, consider a more complex example from sre_parse:: Further, consider a more complex example from sre_parse::
while True: while True:
c = self.next c = self.next
self.__next() self.__next()
if c is None: if c is None:
if not result: if not result:
raise self.error("missing group name") raise self.error("missing group name")
raise self.error("missing %s, unterminated name" % terminator,
len(result))
if c == terminator:
if not result:
raise self.error("missing group name", 1)
break
result += c
return result
This is the natural way to write this code given current Python
loop control syntax. However, given ``break if``, it would be more
natural to write this as follows::
while:
c = self.next
self.__next()
break if c is None or c == terminator
result += c
if not result:
raise self.error("missing group name")
elif c is None:
raise self.error("missing %s, unterminated name" % terminator, raise self.error("missing %s, unterminated name" % terminator,
len(result)) len(result))
return result if c == terminator:
if not result:
raise self.error("missing group name", 1)
break
result += c
return result
This form moves the error handling out of the loop body, leaving the This is the natural way to write this code given current Python
loop logic much more understandable. While it would certainly be loop control syntax. However, given ``break if``, it would be more
possible to write the code this way using the current syntax, the natural to write this as follows::
proposed syntax makes it more natural to write it in the clearer form.
The proposed syntax also provides a natural, Pythonic spelling of while:
the classic ``repeat ... until <expression>`` construct found in c = self.next
other languages, and for which no good syntax has previously been self.__next()
found for Python:: break if c is None or c == terminator
result += c
if not result:
raise self.error("missing group name")
elif c is None:
raise self.error("missing %s, unterminated name" % terminator,
len(result))
return result
while: This form moves the error handling out of the loop body, leaving the
... loop logic much more understandable. While it would certainly be
break if <expression> possible to write the code this way using the current syntax, the
proposed syntax makes it more natural to write it in the clearer form.
The tarfile module, for example, has a couple of "read until" loops like The proposed syntax also provides a natural, Pythonic spelling of
the following:: the classic ``repeat ... until <expression>`` construct found in
other languages, and for which no good syntax has previously been
found for Python::
while True: while:
s = self.__read(1) ...
if not s or s == NUL: break if <expression>
break
With the new syntax this would read more clearly:: The tarfile module, for example, has a couple of "read until" loops like
the following::
while: while True:
s = self.__read(1) s = self.__read(1)
break if not s or s == NUL if not s or s == NUL:
The case for extending this syntax to ``continue`` is less strong,
but buttressed by the value of consistency.
It is much more common for a ``continue`` statement to be at the
end of a multiline if suite, such as this example from zipfile ::
while True:
try:
self.fp = io.open(file, filemode)
except OSError:
if filemode in modeDict:
filemode = modeDict[filemode]
continue
raise
break break
The only opportunity for improvement the new syntax would offer for With the new syntax this would read more clearly::
this loop would be the omission of the ``True`` token.
On the other hand, consider this example from uuid.py:: while:
s = self.__read(1)
break if not s or s == NUL
for i in range(adapters.length): The case for extending this syntax to ``continue`` is less strong,
ncb.Reset() but buttressed by the value of consistency.
ncb.Command = netbios.NCBRESET
ncb.Lana_num = ord(adapters.lana[i]) It is much more common for a ``continue`` statement to be at the
if win32wnet.Netbios(ncb) != 0: end of a multiline if suite, such as this example from zipfile ::
while True:
try:
self.fp = io.open(file, filemode)
except OSError:
if filemode in modeDict:
filemode = modeDict[filemode]
continue continue
ncb.Reset() raise
ncb.Command = netbios.NCBASTAT break
ncb.Lana_num = ord(adapters.lana[i])
ncb.Callname = '*'.ljust(16)
ncb.Buffer = status = netbios.ADAPTER_STATUS()
if win32wnet.Netbios(ncb) != 0:
continue
status._unpack()
bytes = status.adapter_address[:6]
if len(bytes) != 6:
continue
return int.from_bytes(bytes, 'big')
This becomes:: The only opportunity for improvement the new syntax would offer for
this loop would be the omission of the ``True`` token.
for i in range(adapters.length): On the other hand, consider this example from uuid.py::
ncb.Reset()
ncb.Command = netbios.NCBRESET
ncb.Lana_num = ord(adapters.lana[i])
continue if win32wnet.Netbios(ncb) != 0
ncb.Reset()
ncb.Command = netbios.NCBASTAT
ncb.Lana_num = ord(adapters.lana[i])
ncb.Callname = '*'.ljust(16)
ncb.Buffer = status = netbios.ADAPTER_STATUS()
continue if win32wnet.Netbios(ncb) != 0
status._unpack()
bytes = status.adapter_address[:6]
continue if len(bytes) != 6
return int.from_bytes(bytes, 'big')
This example indicates that there are non-trivial use cases where for i in range(adapters.length):
``continue if`` also improves the readability of the loop code. ncb.Reset()
ncb.Command = netbios.NCBRESET
ncb.Lana_num = ord(adapters.lana[i])
if win32wnet.Netbios(ncb) != 0:
continue
ncb.Reset()
ncb.Command = netbios.NCBASTAT
ncb.Lana_num = ord(adapters.lana[i])
ncb.Callname = '*'.ljust(16)
ncb.Buffer = status = netbios.ADAPTER_STATUS()
if win32wnet.Netbios(ncb) != 0:
continue
status._unpack()
bytes = status.adapter_address[:6]
if len(bytes) != 6:
continue
return int.from_bytes(bytes, 'big')
It is probably significant to note that all of the examples selected This becomes::
for this PEP were found by grepping the standard library for ``while
True`` and ``continue``, and the relevant examples were found in for i in range(adapters.length):
the first four modules inspected. ncb.Reset()
ncb.Command = netbios.NCBRESET
ncb.Lana_num = ord(adapters.lana[i])
continue if win32wnet.Netbios(ncb) != 0
ncb.Reset()
ncb.Command = netbios.NCBASTAT
ncb.Lana_num = ord(adapters.lana[i])
ncb.Callname = '*'.ljust(16)
ncb.Buffer = status = netbios.ADAPTER_STATUS()
continue if win32wnet.Netbios(ncb) != 0
status._unpack()
bytes = status.adapter_address[:6]
continue if len(bytes) != 6
return int.from_bytes(bytes, 'big')
This example indicates that there are non-trivial use cases where
``continue if`` also improves the readability of the loop code.
It is probably significant to note that all of the examples selected
for this PEP were found by grepping the standard library for ``while
True`` and ``continue``, and the relevant examples were found in
the first four modules inspected.
Copyright Copyright
========= =========
This document is placed in the public domain. This document is placed in the public domain.