On Tue, Apr 5, 2011 at 9:46 AM, Brett Cannon <brett@python.org> wrote:While I agree with the PEP in principle, I disagree with the way this
> 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.
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 collections import UserList
>>> from test.support import import_fresh_module
>>> c_heapq = import_fresh_module('heapq', fresh=['_heapq'])
>>> py_heapq = import_fresh_module('heapq', blocked=['_heapq'])
>>> 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 | ncoghlan@gmail.com | Brisbane, Australia