Dictionary View Objects 101

Learning about dynamic view objects in Python

Photo by Dmitry Ratushny on Unsplash

Many languages have their own dictionaries, these are “general-purpose data structures for storing a group of objects” (Wikipedia, 2019). In the python dictionary, some of the methods return view objects. These view objects are dynamic view objects, meaning that when the dictionary changes, the view reflects these changes. Dict view objects also support set-like operations, membership tests, and more built-in functions. This article will explore dictionary view objects in greater detail with the aim of helping you to understand the basic concepts at play here, as well as share some examples of how you may encounter them as you continue on your coding journey.


Topics covered in this story.

Photo by Author

Dictionary View Objects

The objects returned by dict.keys(), dict.values(), and dict.items() are view objects. They provide a dynamic view of the dictionary’s entries, which means that when the dictionary changes, the view reflects these changes.

dict.keys()

dict.keys() return a new view of dictionary keys. If we update the dictionary then the dictionary view objects are also dynamically updated.

d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
k = d.keys()
print(k)
# Output:dict_keys(['a', 'b', 'c', 'd'])       
print(type(k))
# Output:<class 'dict_keys'>                   

# updating the dictionary                      
d['e'] = 5
print(d)
# dynamic view object is updated automatically 
print(k)
# Output:dict_keys(['a', 'b', 'c', 'd', 'e'])

dict.values()

dict.values() return a new view of the dictionary’s values. If we update the dictionary then the dictionary view objects are also dynamically updated.

d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
v = d.values()
print(v)
# Output:dict_values([1, 2, 3, 4])
print(type(v))
# Output:<class 'dict_values'>

# updating the dictionary
d['e'] = 5
print(d)#Output:{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
# dynamic view object is updated automatically
print(v)
# Output:dict_values([1, 2, 3, 4, 5])

dict.items()

These return a new view of the dictionary’s items ((key, value) pairs). If we update the dictionary then the dictionary view objects are also dynamically updated.

d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
i = d.items()
print(i)
# Output:dict_items([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
print(type(i))
# Output:<class 'dict_items'>

# updating the dictionary
d['e'] = 5
print(d)#Output:{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
# dynamic view object is updated automatically
print(i)
# Output:dict_items([('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)])

Built-in functions supported by dictionary view objects:

  1. len(dictview)
  2. iter(dictview)
  3. reversed(dictview)
  4. sorted(dictview)
  5. list(dictview)

1.len(dictview)
Returns the number of entries in the dictionary.

d = {'g': 1, 'b': 2, 'c': 3, 'd': 4}
k=d.keys()
print (len(k))#Output:4

v=d.values()
print (len(v))#Output:4

i=d.items()
print (len(i))#Output:4

2. iter(dictview)
Returns an iterator over the keys, values, or items (represented as tuples of (key, value)) in the dictionary. Keys, values, and items are iterated over insertion order.

iter(dict) will return an iterator over keys alone.

Example 1. Iterating over keys- Converting iterator to list using list() constructor:

d = {'g': 1, 'b': 5, 'c': 3, 'd': 4}
k=d.keys()
print (iter(d))#Output:<dict_keyiterator object at 0x011DE050>
#Converting iterator to list
print (list(iter(d)))#Output:['g', 'b', 'c', 'd']

Example 2. Iterating over the values- Accessing elements in iterator using for loop:

d = {'g': 1, 'b': 5, 'c': 3, 'd': 4}
v=d.values()
print (iter(v))#Output:<dict_valueiterator object at 0x011DE050>
#Accessing elements in iterator using for loop
for i in iter(v):
    print (i)
'''
Output:
1
5
3
4
'''

Example 3. Iterating over the items. Accessing the elements in the iterator using the next() function:

d = {'g': 1, 'b': 5, 'c': 3, 'd': 4}
i=d.items()
i1=iter(i)#Output:<dict_valueiterator object at 0x011DE050>
#Accessing elements in itertaor using next() fucntion
print (next(i1))#Output:('g', 1)
print (next(i1))#Output:('b', 5)
print (next(i1))#Output:('c', 3)

Example 4. Iterating over the dictionary (It will iterate over keys alone):

d = {'g': 1, 'b': 5, 'c': 3, 'd': 4}
print (iter(d))#Output:<dict_keyiterator object at 0x011DE050>
print (list(iter(d)))#Output:['g', 'b', 'c', 'd']

Example 5. Create a list of (value, key) pairs from the dictionary:

d = {'g': 1, 'b': 5, 'c': 3, 'd': 4}
z=zip(d.values(),d.keys())
print (z)#Output:<zip object at 0x03199528>
print (list(z))#Output:[(1, 'g'), (5, 'b'), (3, 'c'), (4, 'd')]

Example 6. Convert a dictionary to value: key pair:

d = {'g': 1, 'b': 5, 'c': 3, 'd': 4}
d1={v:k for v in d.values() for k in d.keys()}
print (d1)#Output:{1: 'd', 5: 'd', 3: 'd', 4: 'd'}

NB: Iterating views while adding or deleting entries in the dictionary may raise a RuntimeError or fail to iterate over all entries.

d = {'g': 1, 'b': 5, 'c': 3, 'd': 4}
for i in iter(d.keys()):
if i=='c':
del d[i]
    print (i)

#Output:RuntimeError: dictionary changed size during iteration

3. reversed(dictview)

Returns a reverse iterator over the keys, values, or items of the dictionary. The view will be iterated in reverse order of the insertion. Changed in version 3.8: Dictionary views are now reversible.

reversed(dict)-Returns a reverse iterator over keys alone in the dictionary

d = {'g': 1, 'b': 5, 'c': 3, 'd': 4}
k=reversed(d.keys())
print (list(k))#Output:['d', 'c', 'b', 'g']

v=reversed(d.values())
print (list(v))#Output:[4, 3, 5, 1]

i=reversed(d.items())
print (list(i))#Output:[('d', 4), ('c', 3), ('b', 5), ('g', 1)]

#return a reversed iterator of keys alone
d1=reversed(d)
print (list(d1))#Output:['d', 'c', 'b', 'g']

4.sorted(dictview)

Return a sorted list over the keys, values, or items of the dictionary.

sorted(dict) -Return a sorted list of keys alone in the dictionary.

d = {'g': 1, 'b': 5, 'c': 3, 'd': 4}
print (sorted(d.keys()))#Output:['b', 'c', 'd', 'g']

print (sorted(d.values()))#Output:[1, 3, 4, 5]

print (sorted(d.items()))#Output:[('b', 5), ('c', 3), ('d', 4), ('g', 1)]

d1=print (sorted(d))#Output:['b', 'c', 'd', 'g']

5. list(dictview)

Return a list over the keys, values, or items of the dictionary.

list(dict) -Return a list of keys alone in the dictionary.

d = {'g': 1, 'b': 5, 'c': 3, 'd': 4}
print (list(d.keys()))#Output:['g', 'b', 'c', 'd']

print (list(d.values()))#Output:[1, 5, 3, 4]

print (list(d.items()))#Output:[('g', 1), ('b', 5), ('c', 3), ('d', 4)]

d1=print (list(d))#Output:['g', 'b', 'c', 'd']

Membership Test:

x in dictview

Return True if x is in the underlying dictionary’s keys, values or items (in the latter case, x should be a (key, value) tuple).

x in dict

Returns True if x is in the dictionary’s keys.

d = {'g': 1, 'b': 5, 'c': 3, 'd': 4}
print ('a' in d.keys())#Output:False
print ('b' in d.keys())#Output:True
print (1 in d.values())#Output:True
print (2 in d.values())#Output:False
print (('g',1) in d.items())#Output:True

print (1 in d)#Output:False
print ('b' in d)#Output:True

Equality Comparison between the dictview objects.

An equality comparison between one dict.values() view and another will always return False. This also applies when comparing dict.values() to itself.

d = {'g': 1, 'b': 5, 'c': 3, 'd': 4}
d1= {'g': 1, 'b': 5, 'c': 3, 'd': 4}
v=d.values()
v1=d.values()
print (v)#Output:dict_values([1, 5, 3, 4])
print (v1)#Output:dict_values([1, 5, 3, 4])
print (v==v1)#Output:False

An equality comparison between one dict.keys() view and another will return True if both contain the same elements (regardless of ordering). Otherwise, it returns False.

d = {'g': 1, 'b': 5, 'c': 3, 'd': 4}
d1= {'b':5,'g':1, 'c': 3, 'd': 4}
k=d.keys()
k1=d1.keys()
#Comparing dictionaries having same keys(different order)
print (k==k1)#Output:True

d2={'a':3}
#Comparing dictionaries having different keys
print (d.keys()==d2.keys())#Output:False

An equality comparison between one dict.items() view and another will return True if both contain the same elements(regardless of ordering). Otherwise, it returns False.

d = {'g': 1, 'b': 5, 'c': 3, 'd': 4}
d1= {'b':5,'g':1, 'c': 3, 'd': 4}
k=d.items()
k1=d1.items()
#Comparing dictionaries having same items(different order)
print (k==k1)#Output:True

d2={'a':3}
#Comparing dictionaries having different items
print (d.items()==d2.items())#Output:False

Dictionaries compare equal if and only if they have the same (key, value) pairs (regardless of ordering).

d = {'g': 1, 'b': 5, 'c': 3, 'd': 4}
d1= {'b':5,'g':1 ,'c': 3, 'd': 4}
print (d==d1)#Output:True

Set Operation supported by dict view objects

The set doesn’t contain duplicate elements. Similarly, the dictionary also contains unique keys only. So keys views are set-like since their entries are unique and hashable.

If all values are hashable, so that (key, value) pairs are unique and hashable, then the item’s view is also set-like. Values views are not treated as set-like since the entries are generally not unique.

For set-like views, all of the operations defined for the abstract base class collections.abc.Set are available (for example, ==, <, or ^).

Refer to my story for all set operations

Example 1. Set Operations supported in keys views:

d = {'f': 1, 'b': 5, 'c': 3, 'd': 4}
d1= {'b':5,'e':1, 'a': 3}

k=d.keys()
k1=d1.keys()

print (k > k1)#Output:False

print (k & k1) #Output:{'b'}

print (k ^ k1) #Output:{'f', 'e', 'a', 'd', 'c'}

print (k | k1) #Output:{'d', 'b', 'e', 'c', 'f', 'a'}

Example 2. Performing set operations on values views will raise TypeError:

d = {'f': 1, 'b': 5, 'c': 3, 'd': 4}
d1= {'b':5,'e':1, 'a': 3}

v=d.values()
v1=d1.values()

print (v > v1)#Output:TypeError: '>' not supported between instances of 'dict_values' and 'dict_values'

Example 3. Performing set operations on item’s views which contain hashable values:

All of Python’s immutable built-in objects are hashable. Mutable containers (such as lists or dictionaries) are not hashable. If all values are hashable, so that (key, value) pairs are unique and hashable, then the items view is also set-like. In this example, the values mentioned are hashable. So, we can perform set operations on items view:

d = {'f': 1,'a':2,'c':3}
d1 = {'f': 1,'c':3}

i=d.items()
i1=d1.items()

print (i > i1)#Output:True

print (i & i1) #Output:{('f', 1), ('c', 3)}

print (i ^ i1) #Output:{('a', 2)}

print (i | i1) #Output:{('f', 1), ('c', 3), ('a', 2)}

Example 4. Performing set operations on item’s views that contain not hashable values:

d = {'f': 1,'a':2,'c':3}
d1 = {'f': [1,2],'c':3}

i=d.items()
i1=d1.items()

print (i > i1)#Output:TypeError: unhashable type: 'list'

Note: Python version used is 3.8.1.

Conclusion:

In this article we have covered a lot of concepts including that dictionary view objects (dict.keys(), dict.values(), and dict.items()) are dynamic view objects, that when dictionary entries change, view objects are also updated dynamically, and that built-in functions and membership tests on dict will work on keys alone, whereas on dictview they will work on keys, values, and items. Keys views and items view with hashable values are set like and we can perform set operations on that. Set operations are not supported in values-view. I hope that you have found this article helpful, thanks for reading!


Resources(Python Documentation):

Dictionary view objects

dict.values()

dict.items()

dict.keys()

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s