On 2/17/06, Nick Coghlan <ncoghlan@gmail.com> wrote:
And this is where the question of whether has_key/__having__ return True or False when default_factory is set is important. If they return False, then the LBYL (if key in d:) and EAFTP (try/except) approaches give *different answers*.
More importantly, LBYL will never have side effects, whereas EAFTP may.
If the methods always return True (as Martin suggests), then we retain the current behaviour where there is no real difference between the two approaches. Given the amount of time spent in recent years explaining this fact, I don't think it is an equivalence that should be broken lightly (IOW, I've persuaded myself that I agree with Martin)
The alternative would be to have an additional query API "will_default" that reflects whether or not a given key is actually present in the dictionary ("if key not in d.keys()" would serve a similar purpose, but requires building the list of keys).
Looking at it from the "which invariants hold" POV isn't always the right perspective. Reality is that some amount of code that takes a dict won't work if you give it a dict with a default_factory. Well, that's nothing new. Some code also breaks if you pass it a dict containing key or value types it doesn't expect, or if you pass it an anydbm instance, or os.environ on Windows (which implements case-insensitive keys).
From the POV of someone who decides to use a dict with a default_factory (or overriding on-missing()), having the 'in' operator always return True is d*mn annoying -- it means that any kind of introspection of the dict doesn't work. Take for example the multiset use case. Suppose you're aware that you're using a dict with this special behavior. Now you've built up your multiset and now you want to use it. Part of your app is interested in knowing the list of values associated with each key. But another part may be interested only in whether a particular key hs *any* values associated. If "key in d" returns whether that key is currently present, you can write
if key in d: print "whatever" But under Martin and your proposed semantics, you'd have to write if d.get(key): print "whatever" or (worse) if d[key]: # inserts an empty list into the dict! print "whatever" I'd much rather be able to write "if key in d" and get the result I want... -- --Guido van Rossum (home page: http://www.python.org/~guido/)