PEP 463: Fix some ReST warnings & errors
This commit is contained in:
parent
31ef98498d
commit
0d202d119b
78
pep-0463.txt
78
pep-0463.txt
|
@ -154,18 +154,22 @@ This ternary operator would be between lambda and if/else in
|
|||
precedence.
|
||||
|
||||
Consider this example of a two-level cache::
|
||||
|
||||
for key in sequence:
|
||||
x = (lvl1[key] except KeyError: (lvl2[key] except KeyError: f(key)))
|
||||
# do something with x
|
||||
|
||||
This cannot be rewritten as::
|
||||
|
||||
x = lvl1.get(key, lvl2.get(key, f(key)))
|
||||
|
||||
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
|
||||
backwards; the exception-testing version calculates forwards, as would be
|
||||
expected. The nearest useful equivalent would be::
|
||||
|
||||
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
|
||||
object supporting this functionality.
|
||||
|
||||
|
@ -231,6 +235,7 @@ library, with file names and line numbers correct as of early Feb 2014.
|
|||
Many of these patterns are extremely common.
|
||||
|
||||
Retrieve an argument, defaulting to None::
|
||||
|
||||
cond = args[1] except IndexError: None
|
||||
|
||||
# Lib/pdb.py:803:
|
||||
|
@ -240,6 +245,7 @@ Retrieve an argument, defaulting to None::
|
|||
cond = None
|
||||
|
||||
Fetch information from the system if available::
|
||||
|
||||
pwd = os.getcwd() except OSError: None
|
||||
|
||||
# Lib/tkinter/filedialog.py:210:
|
||||
|
@ -249,6 +255,7 @@ Fetch information from the system if available::
|
|||
pwd = None
|
||||
|
||||
Attempt a translation, falling back on the original::
|
||||
|
||||
e.widget = self._nametowidget(W) except KeyError: W
|
||||
|
||||
# Lib/tkinter/__init__.py:1222:
|
||||
|
@ -259,6 +266,7 @@ Attempt a translation, falling back on the original::
|
|||
|
||||
Read from an iterator, continuing with blank lines once it's
|
||||
exhausted::
|
||||
|
||||
line = readline() except StopIteration: ''
|
||||
|
||||
# Lib/lib2to3/pgen2/tokenize.py:370:
|
||||
|
@ -270,6 +278,7 @@ exhausted::
|
|||
Retrieve platform-specific information (note the DRY improvement);
|
||||
this particular example could be taken further, turning a series of
|
||||
separate assignments into a single large dict initialization::
|
||||
|
||||
# sys.abiflags may not be defined on all platforms.
|
||||
_CONFIG_VARS['abiflags'] = sys.abiflags except AttributeError: ''
|
||||
|
||||
|
@ -281,6 +290,7 @@ separate assignments into a single large dict initialization::
|
|||
_CONFIG_VARS['abiflags'] = ''
|
||||
|
||||
Retrieve an indexed item, defaulting to None (similar to dict.get)::
|
||||
|
||||
def getNamedItem(self, name):
|
||||
return self._attrs[name] except KeyError: None
|
||||
|
||||
|
@ -291,8 +301,8 @@ Retrieve an indexed item, defaulting to None (similar to dict.get)::
|
|||
except KeyError:
|
||||
return None
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
@ -369,13 +379,18 @@ To do this with the statement form of try/except would require a temporary
|
|||
variable, but it's far cleaner as an expression.
|
||||
|
||||
Lib/ipaddress.py:343::
|
||||
|
||||
try:
|
||||
ips.append(ip.ip)
|
||||
except AttributeError:
|
||||
ips.append(ip.network_address)
|
||||
|
||||
Becomes::
|
||||
|
||||
ips.append(ip.ip except AttributeError: ip.network_address)
|
||||
|
||||
The expression form is nearly equivalent to this::
|
||||
|
||||
try:
|
||||
_ = ip.ip
|
||||
except AttributeError:
|
||||
|
@ -383,19 +398,25 @@ The expression form is nearly equivalent to this::
|
|||
ips.append(_)
|
||||
|
||||
Lib/tempfile.py:130::
|
||||
|
||||
try:
|
||||
dirlist.append(_os.getcwd())
|
||||
except (AttributeError, OSError):
|
||||
dirlist.append(_os.curdir)
|
||||
|
||||
Becomes::
|
||||
|
||||
dirlist.append(_os.getcwd() except (AttributeError, OSError): _os.curdir)
|
||||
|
||||
Lib/asyncore.py:264::
|
||||
|
||||
try:
|
||||
status.append('%s:%d' % self.addr)
|
||||
except TypeError:
|
||||
status.append(repr(self.addr))
|
||||
|
||||
Becomes::
|
||||
|
||||
status.append('%s:%d' % self.addr except TypeError: repr(self.addr))
|
||||
|
||||
|
||||
|
@ -427,10 +448,12 @@ In terms of this PEP::
|
|||
x = computation() except default(e)
|
||||
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
|
||||
|
||||
::
|
||||
|
||||
x = try computation() catch MyException:e -> default(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.
|
||||
|
||||
Here's `SML's`__ "handle"::
|
||||
Here's `SML's`__ "handle"
|
||||
|
||||
__ http://www.cs.cmu.edu/~rwh/introsml/core/exceptions.htm
|
||||
|
||||
::
|
||||
|
||||
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
|
||||
|
||||
::
|
||||
|
||||
let x = try computation() with MyException explanation -> default(explanation);;
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
::
|
||||
|
||||
x = try computation() catch MyException as e then default(e)
|
||||
|
||||
|
||||
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
|
||||
write, effectively::
|
||||
write, effectively
|
||||
|
||||
__ http://clojure.org/special_forms#Special%20Forms--(try%20expr*%20catch-clause*%20finally-clause?)
|
||||
|
||||
::
|
||||
|
||||
try(computation(), catch(MyException, explanation, default(explanation)))
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
::
|
||||
|
||||
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.
|
||||
|
@ -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
|
||||
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
|
||||
Python terms than Lisp macros, but something like::
|
||||
Python terms than Lisp macros, but something like
|
||||
|
||||
__ http://wiki.tcl.tk/902
|
||||
|
||||
::
|
||||
|
||||
if {[ catch("computation()") "explanation"]} { default(explanation) }
|
||||
|
||||
|
||||
`Smalltalk`__ is also somewhat hard to map to Python. The basic version
|
||||
would be::
|
||||
would be
|
||||
|
||||
__ http://smalltalk.gnu.org/wiki/exceptions
|
||||
|
||||
::
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
@ -646,9 +690,9 @@ changed in Python 3 for good reason.)
|
|||
|
||||
Additionally, this syntax would allow a convenient way to capture
|
||||
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
|
||||
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.
|
||||
|
||||
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]]
|
||||
|
||||
This could become::
|
||||
|
||||
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,
|
||||
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
|
||||
|
@ -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
|
||||
(ValueError, UnicodeError, AttributeError, EOFError, IOError, OSError,
|
||||
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
|
||||
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
|
||||
of multiple except clauses and/or exception capturing is included. In
|
||||
their absence, the parentheses would be thus::
|
||||
|
||||
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
|
||||
this is a function call, makes this non-compelling. The expression can, of
|
||||
course, be parenthesized if desired, as can the default::
|
||||
|
||||
value = (expr) except ExceptionType: (default)
|
||||
|
||||
|
||||
|
@ -778,9 +828,11 @@ short-hand, though not technically an expression::
|
|||
pass
|
||||
|
||||
For instance, a common use-case is attempting the removal of a file::
|
||||
|
||||
os.unlink(some_file) except OSError: pass
|
||||
|
||||
There is an equivalent already in Python 3.4, however, in contextlib::
|
||||
|
||||
from contextlib import suppress
|
||||
with suppress(OSError): os.unlink(some_file)
|
||||
|
||||
|
|
Loading…
Reference in New Issue