[Python-checkins] peps: PEP 463: Fix some ReST warnings & errors
yury.selivanov
python-checkins at python.org
Fri Feb 21 05:45:04 CET 2014
http://hg.python.org/peps/rev/ce125a2c6047
changeset: 5379:ce125a2c6047
user: Yury Selivanov <yselivanov at sprymix.com>
date: Thu Feb 20 23:44:58 2014 -0500
summary:
PEP 463: Fix some ReST warnings & errors
files:
pep-0463.txt | 206 ++++++++++++++++++++++++--------------
1 files changed, 129 insertions(+), 77 deletions(-)
diff --git a/pep-0463.txt b/pep-0463.txt
--- a/pep-0463.txt
+++ b/pep-0463.txt
@@ -154,18 +154,22 @@
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)))
+
+ 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)
+
+ 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,56 +235,62 @@
Many of these patterns are extremely common.
Retrieve an argument, defaulting to None::
- cond = args[1] except IndexError: None
- # Lib/pdb.py:803:
- try:
- cond = args[1]
- except IndexError:
- cond = None
+ cond = args[1] except IndexError: None
+
+ # Lib/pdb.py:803:
+ try:
+ cond = args[1]
+ except IndexError:
+ cond = None
Fetch information from the system if available::
- pwd = os.getcwd() except OSError: None
- # Lib/tkinter/filedialog.py:210:
- try:
- pwd = os.getcwd()
- except OSError:
- pwd = None
+ pwd = os.getcwd() except OSError: None
+
+ # Lib/tkinter/filedialog.py:210:
+ try:
+ pwd = os.getcwd()
+ except OSError:
+ pwd = None
Attempt a translation, falling back on the original::
- e.widget = self._nametowidget(W) except KeyError: W
- # Lib/tkinter/__init__.py:1222:
- try:
- e.widget = self._nametowidget(W)
- except KeyError:
- e.widget = W
+ e.widget = self._nametowidget(W) except KeyError: W
+
+ # Lib/tkinter/__init__.py:1222:
+ try:
+ e.widget = self._nametowidget(W)
+ except KeyError:
+ e.widget = W
Read from an iterator, continuing with blank lines once it's
exhausted::
- line = readline() except StopIteration: ''
- # Lib/lib2to3/pgen2/tokenize.py:370:
- try:
- line = readline()
- except StopIteration:
- line = ''
+ line = readline() except StopIteration: ''
+
+ # Lib/lib2to3/pgen2/tokenize.py:370:
+ try:
+ line = readline()
+ except StopIteration:
+ line = ''
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: ''
+
+ # Lib/sysconfig.py:529:
+ try:
+ _CONFIG_VARS['abiflags'] = sys.abiflags
+ except AttributeError:
# sys.abiflags may not be defined on all platforms.
- _CONFIG_VARS['abiflags'] = sys.abiflags except AttributeError: ''
-
- # Lib/sysconfig.py:529:
- try:
- _CONFIG_VARS['abiflags'] = sys.abiflags
- except AttributeError:
- # sys.abiflags may not be defined on all platforms.
- _CONFIG_VARS['abiflags'] = ''
+ _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,20 +301,20 @@
except KeyError:
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
+ g = grp.getgrnam(tarinfo.gname)[2] except KeyError: tarinfo.gid
+ u = pwd.getpwnam(tarinfo.uname)[2] except KeyError: tarinfo.uid
- # Lib/tarfile.py:2198:
- try:
- g = grp.getgrnam(tarinfo.gname)[2]
- except KeyError:
- g = tarinfo.gid
- try:
- u = pwd.getpwnam(tarinfo.uname)[2]
- except KeyError:
- u = tarinfo.uid
+ # Lib/tarfile.py:2198:
+ try:
+ g = grp.getgrnam(tarinfo.gname)[2]
+ except KeyError:
+ g = tarinfo.gid
+ try:
+ u = pwd.getpwnam(tarinfo.uname)[2]
+ except KeyError:
+ u = tarinfo.uid
Perform some lengthy calculations in EAFP mode, handling division by
zero as a sort of sticky NaN::
@@ -369,34 +379,45 @@
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)
+
+ try:
+ ips.append(ip.ip)
+ except AttributeError:
+ ips.append(ip.network_address)
+
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::
- try:
- _ = ip.ip
- except AttributeError:
- _ = ip.network_address
- ips.append(_)
+
+ try:
+ _ = ip.ip
+ except AttributeError:
+ _ = ip.network_address
+ 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))
+
+ 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))
+
+ status.append('%s:%d' % self.addr except TypeError: repr(self.addr))
Comparisons with other languages
@@ -427,10 +448,12 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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]]
+
+ 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)))
+
+ 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 @@
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 @@
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 @@
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 @@
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)
--
Repository URL: http://hg.python.org/peps
More information about the Python-checkins
mailing list