Builtin dict should be callable, since a dict defines a function
Bengt Richter
bokr at oz.net
Fri Dec 20 13:28:11 EST 2002
On Fri, 20 Dec 2002 11:54:28 +0100, holger krekel <pyth at devel.trillke.net> wrote:
>Bengt Richter wrote:
>> On Thu, 19 Dec 2002 18:17:03 -0800, Erik Max Francis <max at alcyone.com> wrote:
>>
>> >Bengt Richter wrote:
>> >
>> >> I posted the suggestion in a thread Re: case-insensitive and
>> >> internationalized sort,
>> >> but it occurs to me that the principle is arguable from the abstract
>> >> point of view.
>> >> I.e., a dict implements a function key -> value, so why not let it
>> >> accept a normal
>> >> function arg list (i.e., the tuple) as the argument for its key ->
>> >> value function?
>
>I use this idiom sometimes. From a mathematical point of view,
>functions define mappings/relations between keys and values.
>So your idea makes sense to me (and may not even be marginal :-)
>
>> >> It should be a pretty simple change to provide __call__(self, *args):
>> >> return self[args]
>> >> under the hood, and let hashability chips fall where they will via [].
>> >
>> >But why would this be helpful? A dictionary implements a mappable
>> >interface; a function implements are callable interface. They're
>> >different interfaces; why would dovetailing them into the same interface
>> >be beneficial?
>> You can pass a reference to a dict to something that expects a function,
>> e.g., a sort. You could pass it as a memoized-result proxy function in
>> some context and catch KeyError to take care of LRU caching update, etc.
>> I'm sure many uses would turn up once the obstacle was removed, and
>> people thought of functions as mappings and vice versa ;-)
>
>right, so the key point is *thinking* it this way.
>
>> >It's a simple change, sure, but furthermore it's trivial enough for you
>> >to implement it yourself in a subclass of dict.
>> Yes (as I mentioned less specifically ;-) But not without the performance
>> hit of an extra layer.
>
>class fdict(dict):
> __call__ = dict.__getitem__
>
>no performance hit at all.
I wondered, so I tested:
>>> from time import clock
>>> def test(f, n):
... t12=t23=0.0
... for i in xrange(n):
... t1=clock()
... y=f('x')
... t2=clock()
... t3=clock()
... t12+=t2-t1
... t23+=t3-t2
... return (t12-t23)/n
...
>>> class DSC(dict):
... __call__ = dict.__getitem__
...
>>> d={'x':1}
>>> dsc=DSC()
>>> dsc['x']=1
>>> d
{'x': 1}
>>> dsc
{'x': 1}
>>> dmw=d.__getitem__
>>> test(dsc,100000)
9.4262484684884387e-006
>>> test(dmw,100000)
3.5901983099864767e-006
>>> test(dsc,100000)
9.4990956953597565e-006
>>> test(dmw,100000)
3.7816695190474548e-006
It looks like the class version runs 2-3 times slower than
the direct method wrapper call, AFAICS
>
>I am not sure that it is a good idea to put this into the python dict
>implementation because it would provide *two* obvious ways to use
>a dict-mapping.
>
Well, that's one way to look at it, but not the only one ;-)
>Maybe it makes sense to implement a different __call__ method:
If it does, you can always subclass and override. The good old
__getitem__ interface will still be there ;-)
These are interesting.
>
> def __call__(self, *args):
> for key in args:
> yield self[key]
>
>so that you can get to multiple results with one call.
>There are certainly a lot of variations/additions possible:
Ditto
>
> def __call__(self, *args):
> for key in args:
> if isinstance(key, list):
> yield map(self.__getitem__, key)
> else:
> yield self[key]
>
>which would essentially allow
>
>>>> a=fdict(zip(range(0,10),range(10,20)))
>>>> a([1,2])
><generator object at 0x824e040>
>>>> a([1,2]).next()
>[11, 12]
>>>> map(None, a([1,2], 3,4))
>[[11, 12], 13, 14]
>>>> v1,v2,v3 = a(1,2,3)
>
>Now the real work is to figure out which __call__ semantics
>would satisfy a real need or be really simplifying in everyday
>work.
Well, I think these are all interesting variations, but I don't
think any qualifies as a uniquely simple and unambiguous semantic
for a dict, whereas I think the simple 1:1 key:value mapping function
does. I think that the index:value mappings of lists and tuples also
define simply understood functions, and I would like the unifying alias
of a default __call__ for those analogously, while recognizing that
I can use obj.__getitem__ now.
It's not as if I'm proposing making (x, y, z)() == x(y, z)
;-)
Regards,
Bengt Richter
More information about the Python-list
mailing list