Some anonymous Planet Python poster (at least I couldn't find the author's name on the blog) Christian Wyglendowski asks about a surprising difference between old-style and new-style classes. Since the comments on their blog are closed (which you find out only after pressing Submit), I'll answer here.
The question, slightly paraphrased: given a class
class LameContainerOld: def __init__(self): self._items = {'bar':'test'} def __getitem__(self, name): return self._items[name] def __getattr__(self, attr): return getattr(self._items, attr)
why does the 'in' operator work
>>> container = LameContainerOld() >>> 'foo' in container False >>> 'bar' in container True
when the equivalent new-style class raises a KeyError: 0 exception? Also, why does __getattr__ appear to be called to get the bound __getitem__ method of the dict?
>>> container.__getitem__ <bound method LameContainerNew.__getitem__ of {'bar': 'test'}>
What actually happens here is that LameOldContainer.__getattr__ gets called for special methods such as __contains__ and __repr__. This is why (1) the 'in' check works, and (2) it appears, at first glance, that you get the wrong __getitem__ bound method. If you pay close attention to the output, you'll see that it's the __getitem__ of LameOldContainer; it's just that repr(LameOldContainer()) gets proxied through to the dict.__repr__ when you don't expect it:
Special methods never go through __getattr__ for new-style classes, therefore neither __contains__ nor __repr__ are proxied if you make the container inherit object. If there's no __contains__ method, Python falls back to the sequence protocol and starts calling __getitem__ for numbers 0 through infinity, or until it gets an IndexError exception.>>> container {'bar': 'test'}