[Python-Dev] PEP 463: Exception-catching expressions (original) (raw)

Steven D'Aprano steve at pearwood.info
Thu Mar 6 02:15:38 CET 2014


On Wed, Mar 05, 2014 at 12:57:03PM -0800, Thomas Wouters wrote:

On Thu, Feb 27, 2014 at 1:29 PM, Chris Angelico <rosuav at gmail.com> wrote:

> +Had this facility existed early in Python's history, there would have been > +no need to create dict.get() and related methods;

FWIW, after experimenting and some consideration I've come to the conclusion that this is incorrect. 'd[k] except KeyError: default' is still much broader than dict.get(k):

I don't think your example proves what you think it does. I think it demonstrates a bug in the dict.get method. The documentation for get states clearly that get will never raise KeyError:

Return the value for key if key is in the dictionary, else default.
If default is not given, it defaults to None, so that this method 
never raises a KeyError.

http://docs.python.org/3/library/stdtypes.html#dict.get

but your example demonstrates that in fact it can raise KeyError (albeit under some rather unusual circumstances):

Python 3.4.0rc1+ (default:aa2ae744e701+, Feb 24 2014, 01:22:15) [GCC 4.6.3] on linux Type "help", "copyright", "credits" or "license" for more information. >>> expensivecalculation = hash >>> class C: ... hashcache = {} ... def init(self, value): ... self.value = value ... if value not in self.hashcache: ... self.hashcache[value] = expensivecalculation(value) ... def hash(self): ... return self.hashcache[self.value] ... def eq(self, other): ... return self.value == other ... >>> a, b, c, d = C(1), C(2), C(3), C(4) >>> D = {a: 1, b: 2, c: 3, d: 4} >>> a.value = 5

>>> print("except expr:", (D[a] except KeyError: 'default')) except expr: default

>>> print("dict.get:", D.get(a, 'default')) Traceback (most recent call last): File "", line 1, in File "", line 8, in hash KeyError: 5

According to the documentation, this behaviour is wrong.

Now, you might argue that the documentation is wrong. I'm sympathetic to that argument, but as documented now, dict.get is documented as being logically equivalent to:

try: return d[key] except KeyError: return default

The fact that it actually isn't is an artifact of the specific implementation used. If it were a deliberate design choice, that design is not reflected in the documentation.

Whether the current behaviour is wrong, or the documentation is wrong, is irrelevant to the question of whether or not the developers back in nineteen-ninety-whatever would have choosen to add dict.get had there been syntax for catching the KeyError in an expression. Perhaps they would have argued:

"Sure, you can catch the KeyError yourself, but 'get' is a fundamental operation for mappings, and I think that dict should implement a 'get' method just to be complete."

Or perhaps not. Some developers prefer minimalist APIs, some developers prefer more exhaustive APIs.

Regardless of what might have happened back in 199x when dict.get was first discussed, I think we can agree that an except expression will lower the pressure on Python to add more "get-like" methods, or add default arguments, in the future.

-- Steven



More information about the Python-Dev mailing list