Builtin dict should be callable, since a dict defines a function

Brian McErlean b_mcerlean at yahoo.com
Fri Dec 20 11:50:01 EST 2002


bokr at oz.net (Bengt Richter) wrote in message news:<atuhtp$6ne$0 at 216.39.172.122>...

> [2] NO!! I DON'T want to eliminate the distinction!! I don't know where
> you got that impression. Perhaps there is a misunderstanding running through
> this entire exchange. I don't want to do away with either [] or ().
> That would be a terrible idea, obviously. I just want to be able to make
> use of non-distinction when it functionally exists, and do it without an
> unnecessary performance penalty. Implementation is trivial all around, but
> a fast implementation is trivial in C and equally fast is impossible in Python.

Probably the simplest implementation is to just use:
>>> d = {1:'one', 2:'two}
>>> mapper = d.__getitem__
>>> mapper(1)  1
one

(Also, d.get is available which returns None instead of an exception
if the item doesn't exist.) If anything, I'd expect this to be faster,
since it pre-bound the getitem call (though testing showed me to be
wrong about this - see below).

> I recognize that distinct interfaces are often expressed with obj() vs obj[]
> and they very usefully lead to different aspects of the object. Effectively,
> they are shorthand notations to specify  method search and argument setup.
> They serve very well with dict, list, tuple, function, and class objects
> in conventional ways that implement part of the semantics of the language.
> I'm not suggesting any change to that.

I think theres also some potential for syntactic confusion with nested
tuples.
If dct(1,2) == dct[1,2], it could easily seem a source of surprise
that
dct((1,2)) != dct[(1,2)] but is in fact dct[((1,2),)]
Also, what way do you define dct(1,) - dct[1] or dct[1,]?

> I see no reason not to allow expression of a dict's use in the role of
> its functional twin by simply appending () instead of [], or disallowing
> passing a reference to the dict where it will be interpreted in terms
> of the functional twin. It is obvious that one would prefer the efficiency
> of a dict over coding something like the above, but how about dealing with
> an unpredictable mix where advantages go both ways? Why force an unnecessary
> wrapper?

Passing a reference to a callable dict accessor is trivial.  In fact
passing
d.__getitem__ is if anything removing a layer of wrapper.  Admittedly,
a quick test shows that I might be wrong:

import time
REPS=100000

def test0(d):
    t0=time.time()
    for i in xrange(REPS):
       for j in range(97,123):
           x=d[j]
    t1=time.time()
    print "Time for [] access : ",t1-t0

def test1(f):
    t0=time.time()
    for i in xrange(REPS):
       for j in range(97,123):
           x=f(j)
    t1=time.time()
    print "Time for function access : ",t1-t0

d=dict([(i,chr(i)) for i in range(97,123)])

test0(d)
test1(d.__getitem__)
test1(lambda x:d[x])
gives me
Time for [] access :  2.01300001144
Time for function access :  2.99399995804
Time for function access :  4.36600005627

This could perhaps be attributable to extra overhead for calling
functions (dealing with keyword params etc), as opposed to the
indexing interface.  Anyone more knowledgable care to clarify?

> >since eliminating the distinction is utterly _trivial_ for every single
> >Python programmer to do on their own if they so desire?
> You impose on me type testing burdens and speed degradation for what?
> It's not trivial to write something fast, and you're not talking about
> a trivial **override** of an **existing** method, you're talking about
> having to use suboptimum code to implement something that doesn't exist,
> but that could well exist with no impact whatever on you or any other
> programmer who might choose to ignore it. I don't understand your objection.
> 
> I don't understand what nerve I seem to have poked, but while I'm at it,
> I may as well poke it again by saying I'd like an analogous twin function
> deal for lists ;-) Anyway, ISTM the change in the status quo would go
> largely unnoticed, and could not affect e.g., your programming practices
> at all unless you chose to let it.

You have the "If it ain't broke, don't fix it" nerve, combined with
Python's "preferably one obvious way to do it" guideline.  Introducing
this change doesn't add any real benefit, but does introduce an
alternate way to do something, which means more of the language that
must be learned.  This is a very real penalty - keeping the language
small means that its easier to learn, and easier to understand a
strangers code.  Needless bloat must be fought to the last niggling
detail.  The fact that your proposal adds little means it does qualify
as needless bloat.

There are other reasons also.  Having seperate mapping and calling
interfaces is very valuable - more than once I've had a class with
both __call__ and __getitem__ methods doing very different things.  If
dictionarys implement call as getitem, implementations like this
become inconsistant with dict, the most used mapping object.

> Regards,
> Bengt Richter

Brian McErlean.



More information about the Python-list mailing list