Why is nested dictionaries OK, but nested blocks are not allowed?

Why is nested dictionaries allowed in Python, but nested sets are not allowed?

You can insert dictionaries and change sub-dictionaries on the fly, as shown below:

In [1]: dict1 = {'x':{'a':1, 'b':2}, 'y':{'c':3}}
In [2]: dict2 = {'x':{'a':1, 'b':2}, 'y':{'c':3}}
In [3]: dict1 == dict2
Out[3]: True
In [4]: dict2['x'] = {'d':4}
In [5]: dict1 == dict2
Out[5]: False

      

On the other hand, if you try to put a set in a set, you will get an error saying that this is not possible, since sets are an "unpacked type":

In [6]: set([set(['a'])])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-8e7d044eec15> in <module>()
----> 1 set([set(['a'])])

TypeError: unhashable type: 'set'

      

But that doesn't make sense as dictionaries don't shake either,

In [7]: hash({'a':1})
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-11-44def9788331> in <module>()
----> 1 hash({'a':1})

TypeError: unhashable type: 'dict' 

      

Of course, you can install a fenizset inside the kit,

In [8]: set([frozenset(['a'])])
Out[8]: {frozenset({'a'})}

      

but then you cannot subsequently change the internals of the nested frozenset like you could for nested dictionaries.

As per what I found set

and dict

implemented with a hash table under the hood, so I don't understand why this is valid in one case but not in another.

+3


source to share


2 answers


The problem is, your examples are not similar. No restrictions on dictionary values , only on keys... Here's a more accurate comparison:

>>> d = {{'a': 'b'}: 'c'}

Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    d = {{'a': 'b'}: 'c'}
TypeError: unhashable type: 'dict'
>>> s = {{'a': 'b'}, 'c'}

Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    s = {{'a': 'b'}, 'c'}
TypeError: unhashable type: 'dict'

      

Note that you now get the same behavior as expected; you can think of set

as key only dict

.



You cannot use a mutable / non-removable object as a key in a dictionary or an item in a set, because if you change it in place, it becomes unrecoverable (Python matches __eq__

and __hash__

), so these methods must be implemented to use the custom class as key / element). For more on this, see, for example, Why should dictionary keys be immutable? (different language, but the same principle - all hash tables).

You might also consider looking at The Mighty Dictionary if you're interested in the topic.

+8


source


Since the hash of an item must be unique for its lifetime in order to be meaningfully stored in the hash table, set

(and also list

) cannot be a member set

, as you noticed. However, the dict

object that gets hashed is the key, not the value. Hence, it is legal:

{'x': {1, 2, 3}}  #  a string is hashable

      

and it is not:



{{1, 2, 3}: 'x'}

      

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-1-1cd059738afd> in <module>()
----> 1 {{1, 2, 3}: 'x'}
TypeError: unhashable type: 'set'

      

This is also true for other types neraspakovyvaemyh ( list

and dict

).

+2


source







All Articles