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

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?
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 [].

The idea came up thinking about passing a dict in place of a comparison function,
where it might be practical to build a dict of all printable character pair tuples
and set the values according to how you want them ordered in a sort.

Regards,
Bengt Richter



Tue, 07 Jun 2005 10:04:05 GMT  
 Builtin dict should be callable, since a dict defines a function

Quote:

> 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?
> 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?

It's a simple change, sure, but furthermore it's trivial enough for you
to implement it yourself in a subclass of dict.

--

 __ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/  \ I'm trying to forget / But I can't act as if we never met
\__/ Chante Moore
    PyUID / http://www.alcyone.com/pyos/uid/
 A module for generating "unique" IDs in Python.



Tue, 07 Jun 2005 10:17:03 GMT  
 Builtin dict should be callable, since a dict defines a function


Quote:
> I posted the suggestion in a thread  Re: case-insensitive and

internationalized sort,
Quote:
> 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?
> It should be a pretty simple change to provide __call__(self,

*args): return self[args]
Quote:
> under the hood, and let hashability chips fall where they will via

[].

Do you mean something like this?

Quote:
>>> d=callableDict({'o':1, 't':2, 'f':4})
>>> d

{'t': 2, 'o': 1, 'f': 4}
Quote:
>>> d('o')

1

Quote:
> The idea came up thinking about passing a dict in place of a

comparison function,
Quote:
> where it might be practical to build a dict of all printable

character pair tuples

Quote:
> and set the values according to how you want them ordered in a sort.

or this?

Quote:
>>> class pairs(dict):

...   def  __call__(self,*key): return self[key]
...
Quote:
>>> sorter = pairs({('a','b'):1})
>>> sorter('a','b')

1

You're right, it is simple.

Terry J. Reedy



Tue, 07 Jun 2005 10:46:00 GMT  
 Builtin dict should be callable, since a dict defines a function

Quote:

>> 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?
>> 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 ;-)
Quote:

>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.

I think a dict abstractly does define a function, so IMO it would be a good
thing to allow access to it to be spelled that way. If you want to override
__call__ in a subclass, fine, but let the base class provide a way to
spell the natural default. A mapping is a function, and vv. ;-)

Regards,
Bengt Richter



Tue, 07 Jun 2005 10:59:41 GMT  
 Builtin dict should be callable, since a dict defines a function

Quote:

> You can pass a reference to a dict to something that expects a
> function,
> e.g., a sort.

This has me puzzled.  Are you really suggesting that it would be useful
to represent a sorting as a dictionary whose keys are 2-tuples of every
possible combination of the items (thus requiring that they be
immutable), and that every value is one of -1, 0, or +1 defined in such
a way that they define a well-ordering?  Does that _really_ justifying
defining a callable interface for dictionaries, when if you were to end
up with such a bizarre situation, you could simply do

        D = {...}
        L.sort(lambda x, y, D=D: D((x, y)))

You have really lost me on the possible utility of such a thing.

Mappings are mappings.  Callables are callables.  Folding them into the
same thing doesn't make any sense to me.  In weird corner cases where
you really _do_ want to do such a thing, you're much better off doing it
with a wrapper.  I don't see any justifiable reason to force that
conjoining of different interfaces on _everyone_.

--

 __ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/  \ I'm trying to forget / But I can't act as if we never met
\__/ Chante Moore
    PyUID / http://www.alcyone.com/pyos/uid/
 A module for generating "unique" IDs in Python.



Tue, 07 Jun 2005 11:21:53 GMT  
 Builtin dict should be callable, since a dict defines a function

Quote:


>>> 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?
>>> 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 ;-)

>>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

Um, sorry 'bout that ;-/ I didn't mention it in this thread. I believe I did
in the other one. Anyway, obviously extra layers drag on speed.

But the main thing is that conceptually

           +-----------+
   input-->| something |-->output
           +-----------+

is the same whether you spell it output=something(input) or
output=something[input], but when you pass the object something
somewhere, currently the somewhere has to do unnecessary work
before it can use it for input->|?|->output.

E.g., you can't apply(something, input) for both cases of

    something = {'x':'y'}
and
    def something(arg):
        if arg=='x': return 'y'
        raise KeyError

Why not? They both implement the same input->output function.
IMO it's an artificial limitation on orthogonality not to be
able to pass a dict to a place that expects a function.

Quote:
>hit of an extra layer.

>I think a dict abstractly does define a function, so IMO it would be a good
>thing to allow access to it to be spelled that way. If you want to override
>__call__ in a subclass, fine, but let the base class provide a way to
>spell the natural default. A mapping is a function, and vv. ;-)

Regards,
Bengt Richter


Tue, 07 Jun 2005 11:39:55 GMT  
 Builtin dict should be callable, since a dict defines a function

Quote:

>> You can pass a reference to a dict to something that expects a
>> function,
>> e.g., a sort.

>This has me puzzled.  Are you really suggesting that it would be useful
>to represent a sorting as a dictionary whose keys are 2-tuples of every
>possible combination of the items (thus requiring that they be
>immutable), and that every value is one of -1, 0, or +1 defined in such
>a way that they define a well-ordering?  Does that _really_ justifying

IMO various uses are red herrings. What needs to be justified is an
existing limitation on uniform passing of references to standard objects
that implement the same functionality, just for lack of a trivial alternative
compatible interface.

Quote:
>defining a callable interface for dictionaries, when if you were to end
>up with such a bizarre situation, you could simply do

>    D = {...}
>    L.sort(lambda x, y, D=D: D((x, y)))

>You have really lost me on the possible utility of such a thing.

That's not really the issue ;-)
Quote:

>Mappings are mappings.  Callables are callables.  Folding them into the
>same thing doesn't make any sense to me.  In weird corner cases where

You don't see a commonality in the abstract?

Quote:
>you really _do_ want to do such a thing, you're much better off doing it
>with a wrapper.  I don't see any justifiable reason to force that
>conjoining of different interfaces on _everyone_.

No one would be forced to use an additional interface that doesn't exit now ;-)

Regards,
Bengt Richter



Tue, 07 Jun 2005 11:52:01 GMT  
 Builtin dict should be callable, since a dict defines a function

Quote:

> IMO various uses are red herrings.

You're going to have a hard time selling the idea unless you can give
examples where the change makes things obviously much better.  It's
going to be awfully difficult to do that, since it's _trivial_ to define
a callable interface that simply translates to the mapping interface
yourself.  Since that is so ridiculously easy (one line of code), it's
really hard to justify the change for _everyone_ just because one person
thinks it might be a good idea for abstract reasons.

Quote:
> What needs to be justified is an
> existing limitation on uniform passing of references to standard
> objects
> that implement the same functionality, just for lack of a trivial
> alternative
> compatible interface.

It's not a limitation, it's a clear distinction between mapping and
callable.  There are cases when those purposes may be similar, and cases
where they may not.  As it stands, Python, makes a clear distinction
between the two.  You can define an object that has _both_ a mapping
interface _and_ a callable interface.  Would it be a good idea define
such objects?  I don't know.  But you should be able to do it, since
mapping/subscripting and calling are not the same thing.

What you are proposing _is_ an unnecessary limitation (conjoining two
otherwise separate actions), not  the lifting of a limitation.

Quote:
> You don't see a commonality in the abstract?

There's a commonality in the abstract, of course, in that there is an
interface and that allows you to "do" something.  In a mappable
interface, the "doing" is subscripting; in a callable one, it's calling.
But should you extend that philosophy to everything, you end up with one
"do" operation for every interface.  That's obviously not a pleasant
trend.

Quote:
> No one would be forced to use an additional interface that doesn't
> [exist] now ;-)

But there is no inherent value in adding the equivalence, because it's a
false equivalence.  The two different interfaces exist so that a
distinction can be made between them.  You want to remove that
distinction which is there deliberately.  Why?

--

 __ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/  \ Whoever contends with the great sheds his own {*filter*}.
\__/ Sa'di
    Lsystem / http://www.*-*-*.com/
 A Lindenmayer systems explorer in Python.



Tue, 07 Jun 2005 12:50:10 GMT  
 Builtin dict should be callable, since a dict defines a function

Quote:

> Why not?

Asking "Why not?" is not a very good way to get people to your side when
yours is the marginal opinion.

Quote:
> They both implement the same input->output function.
> IMO it's an artificial limitation on orthogonality not to be
> able to pass a dict to a place that expects a function.

In my opinion, this argument doesn't lead anywhere.  _Lots_ of
interfaces take inputs and return outputs; in fact, you can argue that
_every_ operation does this (or at least results in side effects instead
of returning outputs).  Does that mean that every interface should be
boiled down to a simple "do" command.

Mapping and calling interfaces are analogous in some ways.  But they
exist as separate entities _so that_ a distinction can be made.  You
want to eliminate that distinction.  What purpose would that serve,
since eliminating the distinction is utterly _trivial_ for every single
python programmer to do on their own if they so desire?

--

 __ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/  \ Whoever contends with the great sheds his own {*filter*}.
\__/ Sa'di
    Lsystem / http://www.*-*-*.com/
 A Lindenmayer systems explorer in Python.



Tue, 07 Jun 2005 12:56:15 GMT  
 Builtin dict should be callable, since a dict defines a function

Quote:

>> Why not?

>Asking "Why not?" is not a very good way to get people to your side when
>yours is the marginal opinion.

>> They both implement the same input->output function.
>> IMO it's an artificial limitation on orthogonality not to be
>> able to pass a dict to a place that expects a function.

>In my opinion, this argument doesn't lead anywhere.  _Lots_ of
>interfaces take inputs and return outputs; in fact, you can argue that
>_every_ operation does this (or at least results in side effects instead
>of returning outputs).  Does that mean that every interface should be
>boiled down to a simple "do" command.

>Mapping and calling interfaces are analogous in some ways.  But they
>exist as separate entities _so that_ a distinction can be made.  You

                         [1]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ^^^
Quote:
>want to eliminate that distinction.  What purpose would that serve,

 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^[2]
[1] Yes!! **can** be made, not **must** be made. I want to be able
    to make distinctions too ;-)

[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.

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.

But I _am_ suggesting that a dict _always_ can be viewed as a function
in a very simple, maybe even approaching formal way. Obviously I am just
manipulating representations below, but the abstract idea should be clear?

 >>> d=dict([(x,chr(x)) for x in range(ord('a'),ord('e')+1)])
 >>> d
 {97: 'a', 98: 'b', 99: 'c', 100: 'd', 101: 'e'}

 >>> def d2f(name,d):
 ...     kv = d.items()
 ...     sl = ['def %s(k):'%name,'    if k==%s: return %s'% (`kv[0][0]`,`kv[0][1]`)]
 ...     sl += ['    elif k==%s: return %s'% (`k`,`v`) for k,v in kv[1:]]
 ...     sl += ['    raise KeyError\n']
 ...     return '\n'.join(sl)
 ...
 >>> print d2f('foo',d)
 def foo(k):
     if k==97: return 'a'
     elif k==98: return 'b'
     elif k==99: return 'c'
     elif k==100: return 'd'
     elif k==101: return 'e'
     raise KeyError

 >>> exec  d2f('foo',d)
 >>> d[99]
 'c'
 >>> foo(99)
 'c'

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?

Quote:
>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.

Regards,
Bengt Richter



Tue, 07 Jun 2005 15:47:05 GMT  
 Builtin dict should be callable, since a dict defines a function

Quote:

> 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.

Given the state of affairs, a distinction is made between mappable and
callable.  The builtin dictionary type implements the former and not the
latter.  You're asking it to implement both just for the heck of it.  I
don't think "I see no reason not to allow ..." is going to get you very
far here, since you're the one asking for the change.  The real issue
is, "What are good reasons _to_ allow it?"  The fact that you can wrap a
mappable in a callable interface, lambda or not, with a trivial
one-liner is a good indication that there's no need for it to be done in
the language itself.

Quote:
> 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?

It's not an "unnecessary wrapper."  Someone else may want to override
dicts so that his ExecutableDict has a normal mapping interface _and_ a
callable interface that does something completely unrelated.

I mean, seriously.  How often do you _really_ find yourself wanting to
use a dictionary in a situation that expects a callable and what you
really want is to transform that call into a mapping lookup with
absolutely no changes whatsoever?  I can't think of a single time I've
encountered this, and your example of sorting was, quite frankly, really
stretched.

You're making an argument from theoretical grounds that I don't think
anyone is going to buy on their face value -- that is, anyone who would
be willing to incorporate that change on those theoretical arguments
alone -- so now you're going to have to come up with quite a few
real-world cases where it really is so fabulously convenient to do so
that it wins everyone over.  I don't see that happening.

--

 __ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/  \ But since when can wounded eyes see / If we weren't who we were
\__/ Joi
    7 Sisters Productions / http://www.7sisters.com/
 Web design for the future.



Tue, 07 Jun 2005 17:44:55 GMT  
 Builtin dict should be callable, since a dict defines a function

Quote:



> >> 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 :-)

Quote:
> >> 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.

Quote:
> >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 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.  

Maybe it makes sense to implement a different __call__ method:

    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:

    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

Quote:
>>> a=fdict(zip(range(0,10),range(10,20)))
>>> a([1,2])

<generator object at 0x824e040>

Quote:
>>> 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.

cheers,

    holger



Tue, 07 Jun 2005 18:54:28 GMT  
 Builtin dict should be callable, since a dict defines a function

Quote:

> I recognize that distinct interfaces are often expressed with obj() vs obj[]
> and they very usefully lead to different aspects of the object.

Not to mention "obj." Every object is a function, too, taking its
attributes as arguments and returning a value (or AttributeError).

Your misconception is that you want to make one functional access to an
object the preferred one. This is confusing:

In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.

IOW, why should d(key) be the same as d.__getitem__(key), instead of,
say, d.get(key); the latter has even the advantage of being a total
function. This also points to a solution to your original question: If
you have a dictionary and need a callable, use d.__getitem__.

Regards,
Martin



Tue, 07 Jun 2005 20:16:24 GMT  
 
 [ 19 post ]  Go to page: [1] [2]

 Relevant Pages 

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

2. expanding a list and dict to a *args and **dict

3. Dict can't update with dict-like objects

4. NewBuiltins: added dict() -- inverse of dict.items()

5. Dict to String and String to Dict with Visual Works

6. How to get the Callable of builtin functions

7. callable() builtin-function

8. dict.keys().sort(function)

9. Calling a function, arguments in a dict ??

10. map-like function on dict values?

11. Builtin methods versus Builtin Functions -- help!

12. Tcl8.5: [string map $dict ...] and ordering inside $dict

 

 
Powered by phpBB® Forum Software