pythondictionarysetdictview

Comparing lists with dictviews


Dictionary views "are set-like objects" and can thus be used to compare dictionary contents with other objects. Specifically,

The set-like nature of key-views allows bitwise comparisons. In Python 3, we can find the intersection using the & operator.

hex_ids = {'#b0a7aa': '9976', '#595f5b': '19367', '#9a8f6a': '24095'}
hex_ids.keys()
# dict_keys(['#595f5b', '#9a8f6a', '#b0a7aa'])

{'#c7ccc0', '#9a8f6a', '#8a8e3e'} & hex_ids.keys()
# {'#9a8f6a'}

Oddly, comparing a list and key-view is also possible:

['#c7ccc0', '#9a8f6a', '#8a8e3e'] & hex_ids.keys()
# {'#9a8f6a'}

whereas list and set objects normally cannot be compared this way.

['#c7ccc0', '#9a8f6a', '#8a8e3e'] & set(['#595f5b', '#9a8f6a', '#b0a7aa'])
# TypeError: unsupported operand type(s) for &: 'list' and 'set'

['#c7ccc0', '#9a8f6a', '#8a8e3e'] & {['#595f5b', '#9a8f6a', '#b0a7aa']}
# TypeError: unhashable type: 'list'

Aside from being set-like, why can key-views be compared to lists using bitwise operators?


Tested on: |Python 3.5.2|Python 3.4.4|Python 2.7.12 (using viewkeys())|IPython 5.0.0|


Solution

  • It uses the __rand__ method (short for "reflected and") on the dict_keys type. Note that the reflected functions are only called if the left operand does not support the corresponding operation and the operands are of different types, which is the case here.

    >>> {}.keys().__rand__
    <method-wrapper '__rand__' of dict_keys object at 0x109948f18>
    

    For example:

    >>> {0:0, 1:1}.keys().__rand__([1, 2])
    {1}
    

    For some reason this method was not implemented for sets, which is why that doesn't work:

    >>> {0, 1}.__rand__([1, 2])
    NotImplemented
    

    I don't know the reason for this omission on sets, but I suspect it's probably "nobody has bothered to write it" because you can use set.intersection explicitly instead.