Search code examples
pythondictionarysetpython-datamodel

When can dict_values views be set-like (and why)?


The docs say that values views are not treated as set-like, but sometimes they are:

>>> d = {1: 1}
>>> d.values() | d.keys() 
{1}
>>> d.values() & d.keys() 
{1}
>>> d.values() - d.keys() 
set()

Why implement set-returning set semantics but then fail with an actual set?

>>> d.values() - {1}
TypeError: unsupported operand type(s) for -: 'dict_values' and 'set'

Solution

  • This is actually not dict_values handling the operation(s). The keys_view will strong-arm the operation from the right hand side, by supporting the reflected method(s):

    >>> set().__rsub__({}.values())
    NotImplemented
    >>> {}.keys().__rsub__({}.values())
    set()
    

    For similar reasons, set operations will sometimes work or not work with other dict views:

    # works, because type(d.items()) implements __rsub__
    >>> d.values() - d.items()  
    {1}
    
    # fails, because type(d.values()) does not implement __rsub__
    >>> d.values() - d.values()
    TypeError: unsupported operand type(s) for -: 'dict_values' and 'dict_values'
    

    So, although this behaviour seems to violate duck-typing, the docs remain correct.