Builtin dict should be callable, since a dict defines a funct ion

Bengt Richter bokr at oz.net
Sat Dec 21 10:46:53 EST 2002


On Fri, 20 Dec 2002 12:59:48 -0600, sismex01 at hebmex.com wrote:

>> From: bokr at oz.net [mailto:bokr at oz.net]
>> Sent: Thursday, December 19, 2002 9:00 PM
>> 
>> On Thu, 19 Dec 2002 18:17:03 -0800, Erik Max Francis 
>> <max at alcyone.com> wrote:
>> 
>> >Bengt Richter wrote:
>> >
>> > 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 ;-)
>>
>
>You can already do this.
>
>Let's say you need a function which works like a (callable)
>dictionary for retrieving values. Instead of creating a new
>function or subclassing dict, pass it a reference to:
>
>    d.__getitem__
>
>and voila, there's your reference to a function-behaving-like-
>a-dictionary.
>
True, but it is not quite the same thing. On the surface I was not
asking for more, so your answer (and the same pointed out by others)
is right on as far as it goes (I was a bit chagrined not to have thought
of this obvious thing in the first place). But I still have a nagging
dissatisfaction with the answer.

If I know that a dict will have a _default_ function-style interface
as if its class were defined with __call__ = __getitem__, then I can
make an anonymous collection of function and dict objects, e.g., a list

  fdmix = [f1,f2,d1,d2]

and depend on the callable assumption for all elements.

Now what power does this give me over the following list?

  fdmix2 = [f1,f2,d1.__getitem__, d2.__getitem__]

Well, this list does not carry the same information. I have been
forced to throw away the possibility of distinguishing and acting
differently based on type _if_ that is useful for another use of
the list (e.g., passing the collection to different places).

I admit that a subclass will do what I want, but there is a performance
hit for some reason (see below).

Note that speed could make a lot of difference if you were passing a function
that processed pixels for example:

 >>> import timefuns
 >>> def noop(k): pass
 ...
 >>> d={'xx':123}
 >>> class D(dict): __call__ = dict.__getitem__
 ...
 >>> dc = D(d)
 >>> df = d.__getitem__
 >>> dc.__name__ = 'D inst'
 >>> calls = [(noop,'xx'),(dc,'xx'),(df,'xx')]
 >>> timefuns.timefuns(100000, calls)
            timing oh:  0.000015  ratio
                 noop:  0.000009   1.00
               D inst:  0.000012   1.29
          __getitem__:  0.000004   0.48

Timing overhead is time measured by t1-t0 in
   t0=time.clock()
   t1=time.clock()
where otherwise there is a call to the function as a single line
in between, in thefunction timing loop.

This overhead is subtracted out to get a better relative time between
the functions. The ratios are wrt to the first function in the list.

Note that that d.__getitem__ is almost twice as fast as even just
calling a noop function with the same single parameter.

So I think there is more than one argument in favor of this simple
backwards-compatible change ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list