Allow non-callable default_factory for defaultdict

I have just begun using defaultdict and have found it to be very useful for cleaning up (1) d.setdefault(key, initial_collection) and (2) repeated d.get(key, constant) calls which all use the same constant. (1) is trivial because in most cases, initial_collection is something like "set()" or "[]", and instead I can use "d = defaultdict(set)" or "d = defaultdict(list)" to accomplish the same thing. Now, all those d.setdefault(key...) calls become d[key]. This is much nicer, and I'm sure most of you are familiar with it. (2) is slightly less common, but it still comes up. This can also be handled by defaultdict, using "d = defaultdict(lambda: constant)". Now, all those d.get(key...) calls become d[key]. As with (1), this makes the code significantly nicer, and perhaps some of you have used it. I would like to propose simplifying (2). Instead of using "d = defaultdict(lambda: constant)", it would be nice to be able to use "d = defaultdict(constant)". In 2.5.2:
Obviously, defaultdict is already checking its argument (perhaps it's an assert, but still...), so it knows whether the argument is callable or not. My proposal is that if default_factory is callable or None, the behavior of __missing__ remains the same. Otherwise, the behavior of __missing__ is simply to insert default_factory in the dictionary for the key and return it. I can see one drawback to this: there is a risk of people using defaultdict([]) instead of defaultdict(list) with the idea that they will do the same thing. I think this problem can be easily overcome in the defaultdict documentation by specifically mentioning such a case as a gotcha while also using an example with a non-callable that shows how it is similar to using dict.get(...). Would anyone else find such a change to be helpful? Brandon

Brandon Mintern schrieb:
I think this was exactly one of the reasons that defaultdict takes a factory function. Using a list as the default is a very common use case, and here (as opposed to function parameter defaults) we *can* prevent endless streams of programmers falling into a "trap". Also, this is exactly the kind of situation where lambda fits perfectly. Since we have and keep lambda, I see no reason to complicate the API. This should be documented with defaultdict though. I see an example for a constant default value, but it uses itertools.repeat (!?) Georg

I don't see an extra lambda as that complicated. What is more complicated is that when I see the code: d = defaultdict(foo) I (the reader of the code) can't tell whether foo is the default value or the default function. So I better always write (lambda: foo) unless foo is a constant. Doesn't to have enough benefit to change. --- Bruce On Mon, Jun 2, 2008 at 8:05 AM, Brandon Mintern <bmintern@gmail.com> wrote:

Brandon Mintern schrieb:
I think this was exactly one of the reasons that defaultdict takes a factory function. Using a list as the default is a very common use case, and here (as opposed to function parameter defaults) we *can* prevent endless streams of programmers falling into a "trap". Also, this is exactly the kind of situation where lambda fits perfectly. Since we have and keep lambda, I see no reason to complicate the API. This should be documented with defaultdict though. I see an example for a constant default value, but it uses itertools.repeat (!?) Georg

I don't see an extra lambda as that complicated. What is more complicated is that when I see the code: d = defaultdict(foo) I (the reader of the code) can't tell whether foo is the default value or the default function. So I better always write (lambda: foo) unless foo is a constant. Doesn't to have enough benefit to change. --- Bruce On Mon, Jun 2, 2008 at 8:05 AM, Brandon Mintern <bmintern@gmail.com> wrote:
participants (3)
-
Brandon Mintern
-
Bruce Leban
-
Georg Brandl