On Tue, Apr 5, 2011 at 9:46 AM, Brett Cannon <br...@python.org> wrote: > try: > c_heapq.heappop(Spam()) > except TypeError: > # "heap argument must be a list" > pass > > try: > py_heapq.heappop(Spam()) > except AttributeError: > # "'Foo' object has no attribute 'pop'" > pass > > This kind of divergence is a problem for users as they unwittingly > write code that is CPython-specific. This is also an issue for other > VM teams as they have to deal with bug reports from users thinking > that they incorrectly implemented the module when in fact it was > caused by an untested case.
While I agree with the PEP in principle, I disagree with the way this example is written. Guido has stated in the past that code simply *cannot* rely on TypeError being consistently thrown instead of AttributeError (or vice-versa) when it comes to duck-typing. Code that cares which of the two is thrown is wrong. However, there actually *is* a significant semantic discrepancy in the heapq case, which is that py_heapq is duck-typed, while c_heapq is not: >>> from test.support import import_fresh_module >>> c_heapq = import_fresh_module('heapq', fresh=['_heapq']) >>> py_heapq = import_fresh_module('heapq', blocked=['_heapq']) >>> from collections import UserList >>> class Seq(UserList): pass ... >>> c_heapq.heappop(UserList()) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: heap argument must be a list >>> py_heapq.heappop(UserList()) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/ncoghlan/devel/py3k/Lib/heapq.py", line 140, in heappop lastelt = heap.pop() # raises appropriate IndexError if heap is empty File "/home/ncoghlan/devel/py3k/Lib/collections/__init__.py", line 848, in pop def pop(self, i=-1): return self.data.pop(i) IndexError: pop from empty list Cheers, Nick. P.S. The reason I was bugging Guido to answer the TypeError vs AttributeError question in the first place was to find out whether or not I needed to get rid of the following gross inconsistency in the behaviour of the with statement relative to other language constructs: >>> 1() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'int' object is not callable >>> with 1: pass ... Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'int' object has no attribute '__exit__' Cheers, Nick. -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com