On Mon, Feb 8, 2021 at 4:21 PM Random832
On Sat, Feb 6, 2021 at 5:21 PM Random832
wrote: While we're on the subject of assignment expression limitations, I've occasionally wanted to write something like
try: return a_dict[key] except KeyError: return (a_dict[key] := expression to construct value)
On Sat, Feb 6, 2021, at 01:26, Chris Angelico wrote:
That's what the __missing__ method is for.
Requires a dict subclass
That shouldn't be a big deal in most situations.
Requires that the value be determinable from the key alone [rather than any other variables available in the function containing the above code]
True, but in many situations that IS the case. You're stipulating a situation where: 1) The construction isn't a simple no-arg function (so you can't use defaultdict) 2) The construction can't be figured out from the key alone 3) The cost of construction is high (so you can't use setdefault) 4) There are multiple places where you'd want this behaviour (so you can't just try/except it) Seems a tad narrow to me. Got an actual use-case for this?
On Sat, Feb 6, 2021, at 01:50, Brendan Barnwell wrote:
You can already do that with `return a_dict.setdefault(key, your_expression_here)`. If the expression is expensive to evaluate you can use a short-circuiting conditional expression to guard it.
How exactly would you use a short-circuiting conditional expression to do this?
If you're suggesting `... if key not in a_dict else ...` this creates a race condition, and also involves checking the key in the dictionary twice.
Only against deletion. You could use: a_dict[key] if key in a_dict else a_dict.setdefault(key, big_long_epr) and you're guaranteed that it will use the existing value if it exists. It's possible that the key exists at the condition and then has been deleted before the subscript, but then you have to ask what would happen if you did a regular setdefault and then the key was deleted, and at this point, it's entirely down to the application's semantics (what does it MEAN if something's been deleted while something else is trying to auto-add it?). Checking if a key is in a dict is extremely cheap. Dicts are fundamental to Python, and every implementation will have a highly optimized dict such that you shouldn't need to worry about that kind of cost.
Perhaps a constructdefault method could be added to dict, broadly equivalent to
def constructdefault(self, func): try: return self[key] except KeyError: return (self[key] := func())
you could use self[key] = value = func(); return value; and the same in the original [not part of dict class] snippet I posted above, but the point is this seems so much like exactly the sort of use case that := is intended for, that it comes across as weird that it's not usable.
During discussion of PEP 463, one of the points raised was that many situations like this might be better spelled as exception expressions. That was largely shot down by the fact that, in actual usage, methods like setdefault are FAR easier to work with. I think the same applies here; rather than shoehorning assignment expressions into this job, figure out why it is that both __missing__ and setdefault() aren't suitable, and see if THAT problem can be solved. I've been using assignment expressions since they were added to the language (my primary Python interpreter has, for a number of years, been a master branch build), and they've been incredibly useful, but I have never once run into a situation where the restrictions cause me problems. ChrisA