From: Ethan Furman on 3 Aug 2010 18:07 John Posner wrote: > On 8/3/2010 12:54 PM, Ethan Furman wrote: > > <snip> > >> I think mentioning how __missing__ plays into all this would be helpful. >> Perhaps in the first paragraph, after the colon: >> >> if a key does not currently exist in a defaultdict object, __missing__ >> will be called with that key, which in turn will call a "default value >> factory" to provide a value for that key. > > Thanks, Ethan. As I said (or at least implied) to Christian earlier in > this thread, I don't want to repeat the mistake of the current > description: confusing the functionality provided *by* the defaultdict > class with underlying functionality (the dict type's __missing__ > protocol) that is used in the definition of the class. I just went and read the entry that had the bogus claim -- personally, I didn't see any confusion. I would like to point out the __missing__ is *not* part of dicts (tested on 2.5 and 2.6 -- don't have 2.7 installed yet). Having said that, I think your final paragraph is better than my first paragraph edit. > So I'd rather not mention __missing__ in the first paragraph, which > describes the functionality provided *by* the defaultdict class. How > about adding this para at the end: > > defaultdict is defined using functionality that is available to *any* > subclass of dict: a missing-key lookup automatically causes the > subclass's __missing__ method to be called, with the non-existent key > as its argument. The method's return value becomes the result of the > lookup. > > BTW, I couldn't *find* the coding of defaultdict in the Python 2.6 > library. File collections.py contains this code: > > from _abcoll import * > import _abcoll > __all__ += _abcoll.__all__ > > from _collections import deque, defaultdict > > ... but I ran into a dead end after that. :-( I believe that the > following *could be* the definition of defaultdict: > > class defaultdict(dict): > def __init__(self, factory, *args, **kwargs): > dict.__init__(self, *args, **kwargs) > self.default_factory = factory > > def __missing__(self, key): > """provide value for missing key""" > value = self.default_factory() # call factory with no args > self[key] = value > return value I think it's more along these lines: class defaultdict(dict): def __init__(self, factory=None, *args, **kwargs): dict.__init__(self, *args, **kwargs) self.default_factory = factory def __missing__(self, key): "provide value for missing key" if self.default_factory is None: raise KeyError("blah blah blah") value = self.default_factory() self[key] = value return value ~Ethan~
From: Ethan Furman on 3 Aug 2010 18:15 John Posner wrote: > On 7/31/2010 1:31 PM, John Posner wrote: >> >> Caveat -- there's another description of defaultdict here: >> >> http://docs.python.org/library/collections.html#collections.defaultdict >> >> ... and it's bogus. This other description claims that __missing__ is a >> method of defaultdict, not of dict. __missing__ isn't a method of dict: --> print dir(dict()) ['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__str__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'] I will agree that the current defaultdict description does not make it clear that __missing__ can be defined for *any* subclass of dict, although the dict description does go over this... is that the confusion you are talking about? If not, could you explain? ~Ethan~
From: Christian Heimes on 3 Aug 2010 18:35 > I just went and read the entry that had the bogus claim -- personally, I > didn't see any confusion. I would like to point out the __missing__ is > *not* part of dicts (tested on 2.5 and 2.6 -- don't have 2.7 installed yet). I beg your pardon but you are wrong. __missing__ is available for all *subclasses* of dict since Python 2.5. See http://svn.python.org/view/python/branches/release25-maint/Objects/dictobject.c?revision=81031&view=markup >>> class mydict(dict): .... def __missing__(self, key): .... print "__missing__", key .... raise KeyError(key) .... >>> m = mydict() >>> m[1] __missing__ 1 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in __missing__ KeyError: 1 Christian
From: Ethan Furman on 3 Aug 2010 18:48 Christian Heimes wrote: >> I just went and read the entry that had the bogus claim -- personally, I >> didn't see any confusion. I would like to point out the __missing__ is >> *not* part of dicts (tested on 2.5 and 2.6 -- don't have 2.7 installed yet). > > I beg your pardon but you are wrong. __missing__ is available for all > *subclasses* of dict since Python 2.5. See > http://svn.python.org/view/python/branches/release25-maint/Objects/dictobject.c?revision=81031&view=markup > >>>> class mydict(dict): > ... def __missing__(self, key): > ... print "__missing__", key > ... raise KeyError(key) > ... >>>> m = mydict() >>>> m[1] > __missing__ 1 > Traceback (most recent call last): > File "<stdin>", line 1, in <module> > File "<stdin>", line 4, in __missing__ > KeyError: 1 Perhaps punctuation will help clarify my intent: __missing__ is *not* part of (dict)s, as shown by dir(dict()): ['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__str__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'] And, just to state what is hopefully obvious, if you don't create __missing__ yourself, it still isn't in the subclass: --> class somedict(dict): .... "Is __missing__ defined if I don't define it? Nope." .... --> sd = somedict() --> sd[1] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 1 --> dir(sd) ['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__dict__', '__doc__', '__eq__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__str__', '__weakref__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'] ~Ethan~
From: Christian Heimes on 3 Aug 2010 20:16
> Perhaps punctuation will help clarify my intent: > > __missing__ is *not* part of (dict)s, as shown by dir(dict()): Indeed, that's correct. Can we agree, that __missing__ is an optional feature of the dict interface, that can be implemented in subclasses of dict? Christian |