dict.setdefault_call(), or API variations thereupon

I'd like to propose an addition to `dict` but I'm not necessarily proposing what's written here as the API. When I initially saw the need for this myself, I hastily wrote it as: def setdefault_call(a_dict, key, default_func): try: return a_dict[key] except KeyError: default = default_func() a_dict[key] = default return default If its 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) One potential drawback I see to the concept is that I think there will be a need to explicitly say "no arguments can get passed into this call". Otherwise users may defeat the purpose with constructions like this: d.setdefault_call("foo", list, ["default value"]) I'd mainly like feedback on this concept overall, and if its liked, perhaps an API discussion to follow. Thanks! PS Other APIs I've considered for this are a new keyword argument to the existing `setdefault()`, or perhaps more radically for Python, a new keyword argument to the `dict()` constructor that would get called as an implicit default for `setdefault()` and perhaps used in other scenarios (essentially defining a type for dict values).

On Fri, Nov 2, 2018 at 12:07 PM Alex Shafer <ashafer01@gmail.com> wrote:
Other APIs I've considered for this are a new keyword argument to the existing `setdefault()`, or perhaps more radically for Python, a new keyword argument to the `dict()` constructor that would get called as an implicit default for `setdefault()` and perhaps used in other scenarios (essentially defining a type for dict values).
The time machine has been put to good use here. Are you aware of __missing__ and collections.defaultdict? You just create a defaultdict with a callable (very common to use a class like "list"), and any time you try to use something that's missing, it'll call that to generate a value. from collections import defaultdict d = defaultdict(list) for category, item in some_stuff: d[category].append(item) Easy way to group things into their categories. ChrisA

I use this a lot in my code. Since `setdefault_call` does not exist, here is how I do it: d = {} lookup_d = d.get provide_d = d.setdefault for i in range(1000000): # some large loop l = (lookup_d(somekey)) or (provide_d(somekey, [])) l.append(somevalue) I am not arguing for or against `.setdefault_call` -- I'm just providing information, that I use the referenced behavior hundreds of time in my code. My solution of using `lookup_d(...) or provide_d(...)` is obviously inefficient in that it has to do two dictionary lookups (in the case that the `lookup_d` fails). A `setdefault_call` would be more efficient; though having to create a lambda function, might offset this efficency. So the key issue is readability, not efficiency. On Thu, Nov 1, 2018 at 9:07 PM Alex Shafer <ashafer01@gmail.com> wrote:

On Fri, Nov 2, 2018 at 12:07 PM Alex Shafer <ashafer01@gmail.com> wrote:
Other APIs I've considered for this are a new keyword argument to the existing `setdefault()`, or perhaps more radically for Python, a new keyword argument to the `dict()` constructor that would get called as an implicit default for `setdefault()` and perhaps used in other scenarios (essentially defining a type for dict values).
The time machine has been put to good use here. Are you aware of __missing__ and collections.defaultdict? You just create a defaultdict with a callable (very common to use a class like "list"), and any time you try to use something that's missing, it'll call that to generate a value. from collections import defaultdict d = defaultdict(list) for category, item in some_stuff: d[category].append(item) Easy way to group things into their categories. ChrisA

I use this a lot in my code. Since `setdefault_call` does not exist, here is how I do it: d = {} lookup_d = d.get provide_d = d.setdefault for i in range(1000000): # some large loop l = (lookup_d(somekey)) or (provide_d(somekey, [])) l.append(somevalue) I am not arguing for or against `.setdefault_call` -- I'm just providing information, that I use the referenced behavior hundreds of time in my code. My solution of using `lookup_d(...) or provide_d(...)` is obviously inefficient in that it has to do two dictionary lookups (in the case that the `lookup_d` fails). A `setdefault_call` would be more efficient; though having to create a lambda function, might offset this efficency. So the key issue is readability, not efficiency. On Thu, Nov 1, 2018 at 9:07 PM Alex Shafer <ashafer01@gmail.com> wrote:
participants (3)
-
Alex Shafer
-
Amit Green
-
Chris Angelico