Hum, it looks like the UserDict.get() behavior is an accident due to the
way Mapping.get() is implemented. The comment there says

    'D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.'

but the implementation just tries D[k] and catches KeyError. The
UserDict.__contains__() implementation is explicitly code to avoid
__missing__, since the default Mapping.__contains__() implementation *also*
just calls D[k] and catches KeyError.

More indication that the UserDict.get() behavior is an accident: in
test_userdict.py there's a test for __missing__, test_missing() but it
doesn't test get() at all, only __getitem__().

How were you proposing to fix the situation? I could imagine changing
Mapping.get() to call __contains__() first. That would slow down
Mapping.get() slightly (the default implementation would end up calling
__getitem__() twice if the key is present), but I don't think that's a
grave concern (if people want it faster there are a zillion ways to do
that).

On Wed, Jan 8, 2020 at 9:49 AM Bar Harel <bzvi7...@gmail.com> wrote:

> Sorry for the double post then :-)
>
> As for get(). Current implementation of UserDict returns the default value
> for get() if __missing__() raises KeyError. Which sounds reasonable to me.
> After all, you would logically expect __missing__ to be called for get() as
> you tried to get a non-existing value.
>
> If __missing__ is only a dict thing, then I'll add a note to dict's .get()
> method saying it doesn't call __missing__ for missing values.
> I can also modify UserDict to behave in a consistent manner.
>
> Does that make sense?
>
> On Wed, Jan 8, 2020 at 7:42 PM Guido van Rossum <gu...@python.org> wrote:
>
>> (Note: We received your email twice.)
>>
>> I don't think __missing__ should be called by get() -- get() already has
>> a way to deal with missing keys, and making it use two different mechanisms
>> would be weird (e.g. if get() calls __missing__, is the default value ever
>> used?).
>>
>> To answer your second question, __missing__ is only a dict thing, it is
>> not part of Mapping.
>>
>> On Wed, Jan 8, 2020 at 8:07 AM Bar Harel <bzvi7...@gmail.com> wrote:
>>
>>> Hey guys,
>>>
>>> I was just about to fix dict's get() to call __missing__ if a key
>>> doesn't exist (before returning the default value) but realized that
>>> although small, that patch can cause future issues.
>>> Right now there's an inconsistency:
>>>
>>> >>> from collections import UserDict
>>> >>> class A(dict):
>>> ...  def __missing__(self, key):
>>> ...   print(key)
>>> ...
>>> >>> class B(UserDict):
>>> ...  def __missing__(self, key):
>>> ...   print("UserDict", key)
>>> ...
>>> >>> a = A()
>>> >>> b = B()
>>> >>> a.get(123)
>>> >>> b.get(123)
>>> UserDict 123
>>> >>> a.get(123, "abc")
>>> 'abc'
>>> >>> b.get(123, "abc")
>>> UserDict 123
>>>
>>> The reason for this inconsistency is because the Mapping abc and dict
>>> behave differently.
>>> Dict's get doesn't call __getitem__ which causes the call not to route
>>> to __missing__.
>>> MutableMapping's get calls __getitem__, which UserDict implements as a
>>> check to __missing__ as well.
>>>
>>> According to the doc, the specification requires dict's __getitem__ to
>>> call __missing__. It doesn't say anything about get().
>>>
>>> Should get() call __missing__?
>>>
>>> If it does, things like defaultdict.get() might break. It will however
>>> be more consistent with dict's specification.
>>> If it doesn't, we expect Mapping to not care about __missing__ as it's
>>> only a dict thing, which will require UserDict to override get(). Dict's
>>> get() will need to receive a doc update as well stating __missing__ is not
>>> called.
>>>
>>> Second question is: Is __missing__ only a dict thing, or is it part of
>>> the Mapping ABC?
>>>
>>> I would expect it to be a part of the Mapping ABC, with subclasses not
>>> having to implement it. Right now it's not.
>>>
>>> Looking forward for your inputs,
>>> Bar Harel
>>> _______________________________________________
>>> Python-Dev mailing list -- python-dev@python.org
>>> To unsubscribe send an email to python-dev-le...@python.org
>>> https://mail.python.org/mailman3/lists/python-dev.python.org/
>>> Message archived at
>>> https://mail.python.org/archives/list/python-dev@python.org/message/SDXOEMAEM6KQ3CQCJVBVRT5QNSPAVU6X/
>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>
>>
>>
>> --
>> --Guido van Rossum (python.org/~guido)
>> *Pronouns: he/him **(why is my pronoun here?)*
>> <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
>>
>

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*
<http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/K7ZUPDEG7JLEQ4VRQGIFDTW4BZ3X2R5U/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to