PEP 463: Fix some ReST warnings & errors
This commit is contained in:
parent
31ef98498d
commit
0d202d119b
206
pep-0463.txt
206
pep-0463.txt
|
@ -154,18 +154,22 @@ This ternary operator would be between lambda and if/else in
|
||||||
precedence.
|
precedence.
|
||||||
|
|
||||||
Consider this example of a two-level cache::
|
Consider this example of a two-level cache::
|
||||||
|
|
||||||
for key in sequence:
|
for key in sequence:
|
||||||
x = (lvl1[key] except KeyError: (lvl2[key] except KeyError: f(key)))
|
x = (lvl1[key] except KeyError: (lvl2[key] except KeyError: f(key)))
|
||||||
# do something with x
|
# do something with x
|
||||||
|
|
||||||
This cannot be rewritten as::
|
This cannot be rewritten as::
|
||||||
x = lvl1.get(key, lvl2.get(key, f(key)))
|
|
||||||
|
x = lvl1.get(key, lvl2.get(key, f(key)))
|
||||||
|
|
||||||
which, despite being shorter, defeats the purpose of the cache, as it must
|
which, despite being shorter, defeats the purpose of the cache, as it must
|
||||||
calculate a default value to pass to get(). The .get() version calculates
|
calculate a default value to pass to get(). The .get() version calculates
|
||||||
backwards; the exception-testing version calculates forwards, as would be
|
backwards; the exception-testing version calculates forwards, as would be
|
||||||
expected. The nearest useful equivalent would be::
|
expected. The nearest useful equivalent would be::
|
||||||
x = lvl1.get(key) or lvl2.get(key) or f(key)
|
|
||||||
|
x = lvl1.get(key) or lvl2.get(key) or f(key)
|
||||||
|
|
||||||
which depends on the values being nonzero, as well as depending on the cache
|
which depends on the values being nonzero, as well as depending on the cache
|
||||||
object supporting this functionality.
|
object supporting this functionality.
|
||||||
|
|
||||||
|
@ -231,56 +235,62 @@ library, with file names and line numbers correct as of early Feb 2014.
|
||||||
Many of these patterns are extremely common.
|
Many of these patterns are extremely common.
|
||||||
|
|
||||||
Retrieve an argument, defaulting to None::
|
Retrieve an argument, defaulting to None::
|
||||||
cond = args[1] except IndexError: None
|
|
||||||
|
|
||||||
# Lib/pdb.py:803:
|
cond = args[1] except IndexError: None
|
||||||
try:
|
|
||||||
cond = args[1]
|
# Lib/pdb.py:803:
|
||||||
except IndexError:
|
try:
|
||||||
cond = None
|
cond = args[1]
|
||||||
|
except IndexError:
|
||||||
|
cond = None
|
||||||
|
|
||||||
Fetch information from the system if available::
|
Fetch information from the system if available::
|
||||||
pwd = os.getcwd() except OSError: None
|
|
||||||
|
|
||||||
# Lib/tkinter/filedialog.py:210:
|
pwd = os.getcwd() except OSError: None
|
||||||
try:
|
|
||||||
pwd = os.getcwd()
|
# Lib/tkinter/filedialog.py:210:
|
||||||
except OSError:
|
try:
|
||||||
pwd = None
|
pwd = os.getcwd()
|
||||||
|
except OSError:
|
||||||
|
pwd = None
|
||||||
|
|
||||||
Attempt a translation, falling back on the original::
|
Attempt a translation, falling back on the original::
|
||||||
e.widget = self._nametowidget(W) except KeyError: W
|
|
||||||
|
|
||||||
# Lib/tkinter/__init__.py:1222:
|
e.widget = self._nametowidget(W) except KeyError: W
|
||||||
try:
|
|
||||||
e.widget = self._nametowidget(W)
|
# Lib/tkinter/__init__.py:1222:
|
||||||
except KeyError:
|
try:
|
||||||
e.widget = W
|
e.widget = self._nametowidget(W)
|
||||||
|
except KeyError:
|
||||||
|
e.widget = W
|
||||||
|
|
||||||
Read from an iterator, continuing with blank lines once it's
|
Read from an iterator, continuing with blank lines once it's
|
||||||
exhausted::
|
exhausted::
|
||||||
line = readline() except StopIteration: ''
|
|
||||||
|
|
||||||
# Lib/lib2to3/pgen2/tokenize.py:370:
|
line = readline() except StopIteration: ''
|
||||||
try:
|
|
||||||
line = readline()
|
# Lib/lib2to3/pgen2/tokenize.py:370:
|
||||||
except StopIteration:
|
try:
|
||||||
line = ''
|
line = readline()
|
||||||
|
except StopIteration:
|
||||||
|
line = ''
|
||||||
|
|
||||||
Retrieve platform-specific information (note the DRY improvement);
|
Retrieve platform-specific information (note the DRY improvement);
|
||||||
this particular example could be taken further, turning a series of
|
this particular example could be taken further, turning a series of
|
||||||
separate assignments into a single large dict initialization::
|
separate assignments into a single large dict initialization::
|
||||||
# sys.abiflags may not be defined on all platforms.
|
|
||||||
_CONFIG_VARS['abiflags'] = sys.abiflags except AttributeError: ''
|
|
||||||
|
|
||||||
# Lib/sysconfig.py:529:
|
# sys.abiflags may not be defined on all platforms.
|
||||||
try:
|
_CONFIG_VARS['abiflags'] = sys.abiflags except AttributeError: ''
|
||||||
_CONFIG_VARS['abiflags'] = sys.abiflags
|
|
||||||
except AttributeError:
|
# Lib/sysconfig.py:529:
|
||||||
# sys.abiflags may not be defined on all platforms.
|
try:
|
||||||
_CONFIG_VARS['abiflags'] = ''
|
_CONFIG_VARS['abiflags'] = sys.abiflags
|
||||||
|
except AttributeError:
|
||||||
|
# sys.abiflags may not be defined on all platforms.
|
||||||
|
_CONFIG_VARS['abiflags'] = ''
|
||||||
|
|
||||||
Retrieve an indexed item, defaulting to None (similar to dict.get)::
|
Retrieve an indexed item, defaulting to None (similar to dict.get)::
|
||||||
|
|
||||||
def getNamedItem(self, name):
|
def getNamedItem(self, name):
|
||||||
return self._attrs[name] except KeyError: None
|
return self._attrs[name] except KeyError: None
|
||||||
|
|
||||||
|
@ -291,20 +301,20 @@ Retrieve an indexed item, defaulting to None (similar to dict.get)::
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
Translate numbers to names, falling back on the numbers::
|
Translate numbers to names, falling back on the numbers::
|
||||||
g = grp.getgrnam(tarinfo.gname)[2] except KeyError: tarinfo.gid
|
|
||||||
u = pwd.getpwnam(tarinfo.uname)[2] except KeyError: tarinfo.uid
|
|
||||||
|
|
||||||
# Lib/tarfile.py:2198:
|
g = grp.getgrnam(tarinfo.gname)[2] except KeyError: tarinfo.gid
|
||||||
try:
|
u = pwd.getpwnam(tarinfo.uname)[2] except KeyError: tarinfo.uid
|
||||||
g = grp.getgrnam(tarinfo.gname)[2]
|
|
||||||
except KeyError:
|
# Lib/tarfile.py:2198:
|
||||||
g = tarinfo.gid
|
try:
|
||||||
try:
|
g = grp.getgrnam(tarinfo.gname)[2]
|
||||||
u = pwd.getpwnam(tarinfo.uname)[2]
|
except KeyError:
|
||||||
except KeyError:
|
g = tarinfo.gid
|
||||||
u = tarinfo.uid
|
try:
|
||||||
|
u = pwd.getpwnam(tarinfo.uname)[2]
|
||||||
|
except KeyError:
|
||||||
|
u = tarinfo.uid
|
||||||
|
|
||||||
Perform some lengthy calculations in EAFP mode, handling division by
|
Perform some lengthy calculations in EAFP mode, handling division by
|
||||||
zero as a sort of sticky NaN::
|
zero as a sort of sticky NaN::
|
||||||
|
@ -369,34 +379,45 @@ To do this with the statement form of try/except would require a temporary
|
||||||
variable, but it's far cleaner as an expression.
|
variable, but it's far cleaner as an expression.
|
||||||
|
|
||||||
Lib/ipaddress.py:343::
|
Lib/ipaddress.py:343::
|
||||||
try:
|
|
||||||
ips.append(ip.ip)
|
try:
|
||||||
except AttributeError:
|
ips.append(ip.ip)
|
||||||
ips.append(ip.network_address)
|
except AttributeError:
|
||||||
|
ips.append(ip.network_address)
|
||||||
|
|
||||||
Becomes::
|
Becomes::
|
||||||
ips.append(ip.ip except AttributeError: ip.network_address)
|
|
||||||
|
ips.append(ip.ip except AttributeError: ip.network_address)
|
||||||
|
|
||||||
The expression form is nearly equivalent to this::
|
The expression form is nearly equivalent to this::
|
||||||
try:
|
|
||||||
_ = ip.ip
|
try:
|
||||||
except AttributeError:
|
_ = ip.ip
|
||||||
_ = ip.network_address
|
except AttributeError:
|
||||||
ips.append(_)
|
_ = ip.network_address
|
||||||
|
ips.append(_)
|
||||||
|
|
||||||
Lib/tempfile.py:130::
|
Lib/tempfile.py:130::
|
||||||
|
|
||||||
try:
|
try:
|
||||||
dirlist.append(_os.getcwd())
|
dirlist.append(_os.getcwd())
|
||||||
except (AttributeError, OSError):
|
except (AttributeError, OSError):
|
||||||
dirlist.append(_os.curdir)
|
dirlist.append(_os.curdir)
|
||||||
|
|
||||||
Becomes::
|
Becomes::
|
||||||
|
|
||||||
dirlist.append(_os.getcwd() except (AttributeError, OSError): _os.curdir)
|
dirlist.append(_os.getcwd() except (AttributeError, OSError): _os.curdir)
|
||||||
|
|
||||||
Lib/asyncore.py:264::
|
Lib/asyncore.py:264::
|
||||||
try:
|
|
||||||
status.append('%s:%d' % self.addr)
|
try:
|
||||||
except TypeError:
|
status.append('%s:%d' % self.addr)
|
||||||
status.append(repr(self.addr))
|
except TypeError:
|
||||||
|
status.append(repr(self.addr))
|
||||||
|
|
||||||
Becomes::
|
Becomes::
|
||||||
status.append('%s:%d' % self.addr except TypeError: repr(self.addr))
|
|
||||||
|
status.append('%s:%d' % self.addr except TypeError: repr(self.addr))
|
||||||
|
|
||||||
|
|
||||||
Comparisons with other languages
|
Comparisons with other languages
|
||||||
|
@ -427,10 +448,12 @@ In terms of this PEP::
|
||||||
x = computation() except default(e)
|
x = computation() except default(e)
|
||||||
x = computation() except MyException default() except OtherException other()
|
x = computation() except MyException default() except OtherException other()
|
||||||
|
|
||||||
`Erlang`__ has a try expression that looks like this::
|
`Erlang`__ has a try expression that looks like this
|
||||||
|
|
||||||
__ http://erlang.org/doc/reference_manual/expressions.html#id79284
|
__ http://erlang.org/doc/reference_manual/expressions.html#id79284
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
x = try computation() catch MyException:e -> default(e) end;
|
x = try computation() catch MyException:e -> default(e) end;
|
||||||
x = try computation() catch MyException:e -> default(e); OtherException:e -> other(e) end;
|
x = try computation() catch MyException:e -> default(e); OtherException:e -> other(e) end;
|
||||||
|
|
||||||
|
@ -455,14 +478,20 @@ some dialects, "->" in others.
|
||||||
|
|
||||||
To avoid confusion, I'll write the function calls in Python style.
|
To avoid confusion, I'll write the function calls in Python style.
|
||||||
|
|
||||||
Here's `SML's`__ "handle"::
|
Here's `SML's`__ "handle"
|
||||||
|
|
||||||
__ http://www.cs.cmu.edu/~rwh/introsml/core/exceptions.htm
|
__ http://www.cs.cmu.edu/~rwh/introsml/core/exceptions.htm
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
let x = computation() handle MyException => default();;
|
let x = computation() handle MyException => default();;
|
||||||
|
|
||||||
Here's `OCaml's`__ "try"::
|
Here's `OCaml's`__ "try"
|
||||||
|
|
||||||
__ http://www2.lib.uchicago.edu/keith/ocaml-class/exceptions.html
|
__ http://www2.lib.uchicago.edu/keith/ocaml-class/exceptions.html
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
let x = try computation() with MyException explanation -> default(explanation);;
|
let x = try computation() with MyException explanation -> default(explanation);;
|
||||||
|
|
||||||
let x = try computation() with
|
let x = try computation() with
|
||||||
|
@ -482,17 +511,23 @@ In terms of this PEP, these would be something like::
|
||||||
|
|
||||||
Many ML-inspired but not-directly-related languages from academia mix things
|
Many ML-inspired but not-directly-related languages from academia mix things
|
||||||
up, usually using more keywords and fewer symbols. So, the `Oz`__ would map
|
up, usually using more keywords and fewer symbols. So, the `Oz`__ would map
|
||||||
to Python as::
|
to Python as
|
||||||
|
|
||||||
__ http://mozart.github.io/mozart-v1/doc-1.4.0/tutorial/node5.html
|
__ http://mozart.github.io/mozart-v1/doc-1.4.0/tutorial/node5.html
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
x = try computation() catch MyException as e then default(e)
|
x = try computation() catch MyException as e then default(e)
|
||||||
|
|
||||||
|
|
||||||
Many Lisp-derived languages, like `Clojure,`__ implement try/catch as special
|
Many Lisp-derived languages, like `Clojure,`__ implement try/catch as special
|
||||||
forms (if you don't know what that means, think function-like macros), so you
|
forms (if you don't know what that means, think function-like macros), so you
|
||||||
write, effectively::
|
write, effectively
|
||||||
|
|
||||||
__ http://clojure.org/special_forms#Special%20Forms--(try%20expr*%20catch-clause*%20finally-clause?)
|
__ http://clojure.org/special_forms#Special%20Forms--(try%20expr*%20catch-clause*%20finally-clause?)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
try(computation(), catch(MyException, explanation, default(explanation)))
|
try(computation(), catch(MyException, explanation, default(explanation)))
|
||||||
|
|
||||||
try(computation(),
|
try(computation(),
|
||||||
|
@ -507,9 +542,12 @@ __ http://clhs.lisp.se/Body/m_hand_1.htm
|
||||||
|
|
||||||
The Lisp style is, surprisingly, used by some languages that don't have
|
The Lisp style is, surprisingly, used by some languages that don't have
|
||||||
macros, like Lua, where `xpcall`__ takes functions. Writing lambdas
|
macros, like Lua, where `xpcall`__ takes functions. Writing lambdas
|
||||||
Python-style instead of Lua-style::
|
Python-style instead of Lua-style
|
||||||
|
|
||||||
__ http://www.gammon.com.au/scripts/doc.php?lua=xpcall
|
__ http://www.gammon.com.au/scripts/doc.php?lua=xpcall
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
x = xpcall(lambda: expression(), lambda e: default(e))
|
x = xpcall(lambda: expression(), lambda e: default(e))
|
||||||
|
|
||||||
This actually returns (true, expression()) or (false, default(e)), but I think we can ignore that part.
|
This actually returns (true, expression()) or (false, default(e)), but I think we can ignore that part.
|
||||||
|
@ -541,19 +579,25 @@ colon in the proposal much more obvious::
|
||||||
true if an exception was caught, false otherwise, and you get the value out
|
true if an exception was caught, false otherwise, and you get the value out
|
||||||
in other ways. And it's all built around the the implicit quote-and-exec
|
in other ways. And it's all built around the the implicit quote-and-exec
|
||||||
that everything in Tcl is based on, making it even harder to describe in
|
that everything in Tcl is based on, making it even harder to describe in
|
||||||
Python terms than Lisp macros, but something like::
|
Python terms than Lisp macros, but something like
|
||||||
|
|
||||||
__ http://wiki.tcl.tk/902
|
__ http://wiki.tcl.tk/902
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
if {[ catch("computation()") "explanation"]} { default(explanation) }
|
if {[ catch("computation()") "explanation"]} { default(explanation) }
|
||||||
|
|
||||||
|
|
||||||
`Smalltalk`__ is also somewhat hard to map to Python. The basic version
|
`Smalltalk`__ is also somewhat hard to map to Python. The basic version
|
||||||
would be::
|
would be
|
||||||
|
|
||||||
__ http://smalltalk.gnu.org/wiki/exceptions
|
__ http://smalltalk.gnu.org/wiki/exceptions
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
x := computation() on:MyException do:default()
|
x := computation() on:MyException do:default()
|
||||||
|
|
||||||
… but that's basically Smalltalk's passing-arguments-with-colons
|
... but that's basically Smalltalk's passing-arguments-with-colons
|
||||||
syntax, not its exception-handling syntax.
|
syntax, not its exception-handling syntax.
|
||||||
|
|
||||||
|
|
||||||
|
@ -646,9 +690,9 @@ changed in Python 3 for good reason.)
|
||||||
|
|
||||||
Additionally, this syntax would allow a convenient way to capture
|
Additionally, this syntax would allow a convenient way to capture
|
||||||
exceptions in interactive Python; returned values are captured by "_",
|
exceptions in interactive Python; returned values are captured by "_",
|
||||||
but exceptions currently are not. This could be spelled:
|
but exceptions currently are not. This could be spelled::
|
||||||
|
|
||||||
>>> expr except Exception as e: e
|
>>> expr except Exception as e: e
|
||||||
|
|
||||||
(The inner scope idea is tempting, but currently CPython handles list
|
(The inner scope idea is tempting, but currently CPython handles list
|
||||||
comprehensions with a nested function call, as this is considered
|
comprehensions with a nested function call, as this is considered
|
||||||
|
@ -668,11 +712,15 @@ included in this proposal. A subsequent Python version can add this without
|
||||||
breaking any existing code, as 'as' is already a keyword.
|
breaking any existing code, as 'as' is already a keyword.
|
||||||
|
|
||||||
One example where this could possibly be useful is Lib/imaplib.py:568::
|
One example where this could possibly be useful is Lib/imaplib.py:568::
|
||||||
try: typ, dat = self._simple_command('LOGOUT')
|
|
||||||
except: typ, dat = 'NO', ['%s: %s' % sys.exc_info()[:2]]
|
try: typ, dat = self._simple_command('LOGOUT')
|
||||||
|
except: typ, dat = 'NO', ['%s: %s' % sys.exc_info()[:2]]
|
||||||
|
|
||||||
This could become::
|
This could become::
|
||||||
typ, dat = (self._simple_command('LOGOUT')
|
|
||||||
except BaseException as e: ('NO', '%s: %s' % (type(e), e)))
|
typ, dat = (self._simple_command('LOGOUT')
|
||||||
|
except BaseException as e: ('NO', '%s: %s' % (type(e), e)))
|
||||||
|
|
||||||
Or perhaps some other variation. This is hardly the most compelling use-case,
|
Or perhaps some other variation. This is hardly the most compelling use-case,
|
||||||
but an intelligent look at this code could tidy it up significantly. In the
|
but an intelligent look at this code could tidy it up significantly. In the
|
||||||
absence of further examples showing any need of the exception object, I have
|
absence of further examples showing any need of the exception object, I have
|
||||||
|
@ -701,7 +749,7 @@ of a new type called ExpressionError), or have it look for a tuple named
|
||||||
ExpressionError in the current scope, with a built-in default such as
|
ExpressionError in the current scope, with a built-in default such as
|
||||||
(ValueError, UnicodeError, AttributeError, EOFError, IOError, OSError,
|
(ValueError, UnicodeError, AttributeError, EOFError, IOError, OSError,
|
||||||
LookupError, NameError, ZeroDivisionError). All of these were rejected,
|
LookupError, NameError, ZeroDivisionError). All of these were rejected,
|
||||||
for severa reasons.
|
for several reasons.
|
||||||
|
|
||||||
* First and foremost, consistency with the statement form of try/except
|
* First and foremost, consistency with the statement form of try/except
|
||||||
would be broken. Just as a list comprehension or ternary if expression
|
would be broken. Just as a list comprehension or ternary if expression
|
||||||
|
@ -754,6 +802,7 @@ the expression that could raise? Example::
|
||||||
This is more compelling when one or both of the deferred sub-proposals
|
This is more compelling when one or both of the deferred sub-proposals
|
||||||
of multiple except clauses and/or exception capturing is included. In
|
of multiple except clauses and/or exception capturing is included. In
|
||||||
their absence, the parentheses would be thus::
|
their absence, the parentheses would be thus::
|
||||||
|
|
||||||
value = expr except ExceptionType: default
|
value = expr except ExceptionType: default
|
||||||
value = expr (except ExceptionType: default)
|
value = expr (except ExceptionType: default)
|
||||||
|
|
||||||
|
@ -761,6 +810,7 @@ The advantage is minimal, and the potential to confuse a reader into
|
||||||
thinking the except clause is separate from the expression, or into thinking
|
thinking the except clause is separate from the expression, or into thinking
|
||||||
this is a function call, makes this non-compelling. The expression can, of
|
this is a function call, makes this non-compelling. The expression can, of
|
||||||
course, be parenthesized if desired, as can the default::
|
course, be parenthesized if desired, as can the default::
|
||||||
|
|
||||||
value = (expr) except ExceptionType: (default)
|
value = (expr) except ExceptionType: (default)
|
||||||
|
|
||||||
|
|
||||||
|
@ -778,9 +828,11 @@ short-hand, though not technically an expression::
|
||||||
pass
|
pass
|
||||||
|
|
||||||
For instance, a common use-case is attempting the removal of a file::
|
For instance, a common use-case is attempting the removal of a file::
|
||||||
|
|
||||||
os.unlink(some_file) except OSError: pass
|
os.unlink(some_file) except OSError: pass
|
||||||
|
|
||||||
There is an equivalent already in Python 3.4, however, in contextlib::
|
There is an equivalent already in Python 3.4, however, in contextlib::
|
||||||
|
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
with suppress(OSError): os.unlink(some_file)
|
with suppress(OSError): os.unlink(some_file)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue