On 01.07.20 13:32, Steven D'Aprano wrote:

On Wed, Jul 01, 2020 at 01:07:34PM +0200, Dominik Vilsmeier wrote:

What is the reason for `dict.items` to return a set-like object?
This is the third time I've linked to the PEP:

https://www.python.org/dev/peps/pep-3106/

Thanks for linking to the PEP (to be fair, the second link arrived after
my post).

However reading that PEP only increases the number of question marks.
The PEP speaks mostly about `dict.keys` and occasionally mentions that
similar things can be done for `dict.items`. For example:

> Because of the set behavior, it will be possible to check whether two
dicts have the same keys by simply testing:
> if a.keys() == b.keys(): ...

which makes perfectly sense. But then, immediately after that, it mentions:

> and similarly for .items().

So this means we can do `a.items() == b.items()`. But wait, if the
dicts' items are equal, aren't just the dicts themselves equal? So why
not just compare `a == b`? Why would I want to compare `a.items() ==
b.items()`?

Then, regarding the equality tests (`==`), the Specification section
mentions the following for `dict_keys`:

> To specify the semantics, we can specify x == y as:
> set(x) == set(y)   if both x and y are d_keys instances
> set(x) == y        if x is a d_keys instance
> x == set(y)        if y is a d_keys instance

This makes sense again. And then for `dict_items`:

    # As well as the set operations mentioned for d_keys above.
    # However the specifications suggested there will not work if
    # the values aren't hashable.  Fortunately, the operations can
    # still be implemented efficiently.  For example, this is how
    # intersection can be specified:
    # [...]
    # And here is equality:

    def __eq__(self, other):
        if isinstance(other, (set, frozenset, d_keys)):
            if len(self) != len(other):
                return False
            for item in other:
                if item not in self:
                    return False
            return True
        # [...] handling other cases

This is what I expected how `dict_items` would handle equality tests.
However it doesn't seem to do that:

    >>> self = {'a': []}.items()
    >>> other = {'b'}
    >>> self == other
    TypeError: unhashable type: 'list'
    >>> def __eq__(self, other): ...  # paste the function here
    >>> d_keys = type({}.keys())
    >>> __eq__(self, other)
    False
    >>> self == self
    True

I don't know if it was always implemented like that but at least the PEP
mentions this caveat and I find it surprising as well.
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/NSTPE3SET5YVB7IZP2SUYXNNMCDEZDWK/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to