[Python-ideas] dict.setdefault_call(), or API variations thereupon
Steven D'Aprano
steve at pearwood.info
Fri Nov 2 22:49:11 EDT 2018
On Sat, Nov 03, 2018 at 01:15:04AM +0100, Anders Hovmöller wrote:
>
> > defaultdict:
> > - takes a zero-argument factory function which is
> > unconditionally called when the key is missing.
> >
> > Did I miss any?
> >
> > What we don't have is a version of setdefault where the default is
> > evaluated only on need. That would be a great use-case for Call-By-Name
> > semantics and thunks, if Python supported such :-)
>
> Could you explain what the difference is between defaultdicts "factory
> which is unconditionally called when the key is missing" and "the
> default is evaluated only on need"? To me it seems that
> "unconditionally called when the key is missing" is a complex way of
> saying "called only when needed". I must be missing some nuance here.
Consider the use-case where you want to pass a different default value
to the dict each time:
d.setdefault(key, expensive_function(1, 2, 3))
d.setdefault(key, expensive_function(4, 8, 16))
d.setdefault(key, expensive_function(10, 100, 1000))
The expensive function is eagerly evaluated each time you call
setdefault, whether the result is needed or not.
defaultdict won't help, because your factory function takes no
arguments: there's no way to supply arguments for the factory.
__missing__ won't help, because it only receives the key, not arbitrary
arguments.
We can of course subclass dict and give it a method with the semantics
we want:
d.my_setdefault(key, expensive_function, args=(1, 2, 3), kw={})
but it would be nicer and more expressive if we could tell the
interpreter "don't evaluate expensive_function(...) unless you really
need it".
Other languages have this -- I believe it is called "Call By Need" or
"Call By Name", depending on the precise details of how it works. I call
it delayed evaluation, and Python already has it, but only in certain
special syntactic forms:
spam and <delayed expression>
spam or <delayed expression>
<delayed expression> if condition else <delayed expression>
There are others: e.g. the body of functions, including lambda. But
functions are kinda heavyweight to make and build and call.
--
Steve
More information about the Python-ideas
mailing list