On Fri, Nov 02, 2018 at 09:52:24AM -0700, Chris Barker wrote:
> On Thu, Nov 1, 2018 at 8:34 PM, Steven D'Aprano <st...@pearwood.info> wrote:
> 
> > The bottom line is, if I understand your proposal, the functionality
> > already exists. All you need do is subclass dict and give it a
> > __missing__ method which does what you want.
> 
> 
> or subclass dict and give it a "setdefault_call") method :-)

Well sure, if we're making up our own methods and calling them anything 
we like :-)

The status quo (as I see it):

dict.setdefault:
    - takes an explicit, but eagerly evaluated, default value;

dict.__missing__:
    - requires subclassing to make it work;
    - passes the missing key to the method, so the method can
      decide what value to return;

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

(That's just a half-baked thought, not a concrete proposal.)


> But as I think Guido wasa pointing out, the real difference here is that
> DefaultDict, or any other subclass, is specifying what the default callable
> is for the entire dict, rather than at time of use. 

As you show below, a default callable for the dict is precisely the use-case 
the OP gives:

    l = d.setdefault_call(somekey, list)

would be equivalent to defaultdict(list) and l = d[somekey].

(I think. Have I missed something?)

Nevertheless, Guido's point is reasonable -- if it comes up in practice 
often enough to care.


[...]
> As for the OP's justification:
> 
> """
> If it's not clear, the purpose is to eliminate the overhead of creating an
> empty list or similar in situations like this:
> 
> d = {}
> for i in range(1000000):  # some large loop
>      l = d.setdefault(somekey, [])
>      l.append(somevalue)
>
> # instead...
> 
> for i in range(1000000):
>     l = d.setdefault_call(somekey, list)
>     l.append(somevalue)
> 
> """

Are we sure that the overhead is significantly more than the cost of the 
name lookup of "list" and the expense of calling it?

You do demonstrate a speed difference with defaultdict (thanks for doing 
the timing tests) but the situation isn't precisely comparable to the 
proposed method, since you aren't looking up the name "list" each time 
through the outer loop.

Could construction of the empty list be optimized more? That might 
reduce the benefit even further (at least for the given case, but not 
for the general case of an arbitrarily expensive default).

We keep coming up against the issue of *eager evaluation* versus 
*delayed evaluation*, and I can't help feel that rather that solving 
this problem on an ad-hoc basis each time it comes up, maybe we really 
do need a way to tell the interpreter "delay evaluating this expression 
until needed". Then we could use it anywhere it was important, without 
having to create a plethora of special case setdefault_call() methods 
and the like.



-- 
Steve
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to