[Python-Dev] PEP 463: Exception-catching expressions (original) (raw)
Terry Reedy tjreedy at udel.edu
Thu Mar 6 04:29:44 CET 2014
- Previous message: [Python-Dev] PEP 463: Exception-catching expressions
- Next message: [Python-Dev] PEP 463: Exception-catching expressions
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On 3/5/2014 8:15 PM, Steven D'Aprano wrote:
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]
This is a buggy special method. According to the docs for hash and hash and the general convention on exceptions, a hash method should return an int or raise TypeError.
... 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
This breaks the implied C invariant and makes the object 'a' incoherent and buggy
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.
One could argue that an error raised in a special method is not raised by a function that uses the special method. The docs constantly assume that special methods are coded correctly.
'''bool([x]) Convert a value to a Boolean, using the standard truth testing procedure. If x is false or omitted, this returns False; otherwise it returns True.'''
... unless x.bool raises or returns something other than True/False -- in which case bool itself raises. TypeError: bool should return bool, returned int
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
It appears to be actually equivalent to
key_hash = hash(key) try: return d._hashlookup(key_has) 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,
Given that the choice is that bugs in special methods should not pass silently, I would presume that it is intentional.
that design is not reflected in the documentation.
The docs generally describe behavior in the absence of coding errors.
-- Terry Jan Reedy
- Previous message: [Python-Dev] PEP 463: Exception-catching expressions
- Next message: [Python-Dev] PEP 463: Exception-catching expressions
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]