On 30.06.20 05:08, Steven D'Aprano wrote:

On Tue, Jun 30, 2020 at 11:10:20AM +0900, Inada Naoki wrote:
On Mon, Jun 29, 2020 at 9:12 PM Hans Ginzel <hans@matfyz.cz> wrote:

      
What are the reasons, why object dict.items() is not subscriptable – dict.items()[0]?
Because dict is optimized for random access by key and iteration, but not for
random access by index.
But we're not talking about *dict*, we're talking about dict.items which
returns a set-like object:

    py> from collections.abc import Set
    py> isinstance({}.items(), Set)
    True

So dict.items isn't subscriptable because it's an unordered set, not a
sequence.

What is the reason for `dict.items` to return a set-like object? The values can be non-hashable an in this case the behavior can be surprising:

    >>> {'a': []}.items() & {'b'}
    TypeError: unhashable type: 'list'

Furthermore [the documentation](https://docs.python.org/3/library/stdtypes.html#dict-views) states the following:

> If all values are hashable, so that (key, value) pairs are unique and hashable, then the items view is also set-like.

This sounds like the return type of `dict.items` depended on the actual values contained (which again would be surprising) but actually it doesn't seem to be the case:

    >>> from collections.abc import Set
    >>> isinstance({'a': []}.items(), Set)
    True

`dict.items` could provide all of its "standard" behavior (like membership testing, reversing, etc) without being set-like.

The fact that `==` with `dict.items` raises TypeError for non-hashable values is also a little surprising since it supports membership testing and hence could check `len(self) == len(other) and all(x in self for x in other)` (though that drops the type comparison, but if you cannot have a set, why would you compare them anyway):

    >>> self = {'a': []}.items()
    >>> other = {('a', 1)}
    >>> self == other
    TypeError: unhashable type: 'list'
    >>> len(self) == len(other) and all(x in self for x in other)
    False
    >>> other = [('a', [])]
    >>> len(self) == len(other) and all(x in self for x in other)
    True