Reputation: 122072
Why does dict(list(tuple))
work but not {list(tuple)}
E.g.
>>> dict([('b', 456), ('a', 123)])
{'a': 123, 'b': 456}
>>> {[('b', 456), ('a', 123)]}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
Which part of the CPython code allows for dict([('b', 456), ('a', 123)])
?
Upvotes: 0
Views: 1371
Reputation: 19831
dict
is a class and when you use dict(list(tuple))
it instantiate the class using constructor.
Looking at the documentation for dict
:
Dictionaries can be created by placing a comma-separated list of
key: value
pairs within braces, for example:{'jack': 4098, 'sjoerd': 4127}
or{4098: 'jack', 4127: 'sjoerd'}
, or by the dict constructor.If no positional argument is given, an empty dictionary is created. If a positional argument is given and it is a mapping object, a dictionary is created with the same
key-value
pairs as the mapping object. Otherwise, the positional argument must be aniterable
object. Each item in theiterable
must itself be aniterable
with exactly two objects. The first object of each item becomes a key in the new dictionary, and the second object the corresponding value. If a key occurs more than once, the last value for that key becomes the corresponding value in the new dictionary.
When you use {list(tuple)}
it tries to create a set
object.
A set object is an unordered collection of distinct
hashable
objects.
But here you have used a list element which is a mutable container and is not hashable which leads to the error:
TypeError: unhashable type: 'list'
There is a nice explanation on Why Lists Can't Be Dictionary Keys?, and the same behavior applies to set members as well.
Upvotes: 1
Reputation: 1938
dict(list(tuple))
create a new dict use the dict()
constructor. And here is what he does
def __init__(self, seq=None, **kwargs): # known special case of dict.__init__
"""
dict() -> new empty dictionary
dict(mapping) -> new dictionary initialized from a mapping object's
(key, value) pairs
dict(iterable) -> new dictionary initialized as if via:
d = {}
for k, v in iterable:
d[k] = v
dict(**kwargs) -> new dictionary initialized with the name=value pairs
in the keyword argument list. For example: dict(one=1, two=2)
"""
If you use {list(tuple)}
, you are using set literals. It creates a new set
, not dict
For dict literals you need minimum a pair of two values separated by a colon. (Don't ask me why ;). This is definition of Python)
To create a set
or a dict
, the keys (of dict
) or values (of set
) must be hashable. The definition says:
An object is hashable if it has a hash value which never changes during its lifetime
A list
is a mutable sequence. So list
is unhashable. That's why you got the error message
TypeError: unhashable type: 'list'
If you want to create a new dict
use braces from a list(tuple)
, you can use dict comprehension. (But only supported on Python 3)
{a,b for a,b in list(tuple)}
P/S: dict literals is a little more performance than dict()
Upvotes: 0
Reputation: 20336
{}
can be used for both sets and dictionaries. For example, {8: 2}
is a dictionary, but {1, 2, 3, 4}
is a set. Since you gave no key, Python assumes that you want a set. A set depends on having hashable items, so it complains when you give it a list.
If you want to use a literal, try a comprehension:
{k: v for k, v in mylist}
Upvotes: 7
Reputation: 280837
Just like with ["asdf"]
and list("asdf")
or str(thing)
and "thing"
, calling the dict constructor on a thing does something completely different from surrounding it with braces.
When you construct a dict with braces, you're supposed to write out key-value pairs explicitly:
{'b': 456, 'a': 123}
When you just write {thing}
, Python sees that you've written a single item instead of key-value pairs, and it instead tries to build a single-element set containing that thing
. This fails, because the thing in the braces is a list and lists aren't hashable.
When you construct a dict with the dict
constructor, you can pass in a single object used to initialize the dict. This object can either be another mapping, which will be copied into the dict, or a sequence of key-value pairs represented as tuples:
dict([('b', 456), ('a', 123)])
You cannot use colon notation:
dict('b': 456, 'a': 123) # Syntax error
You can use keyword arguments, since the constructor also allows you to provide string keys as keyword arguments, a syntax that the braces notation doesn't support:
dict(b=456, a=123) # Works
{b=456, a=123) # Syntax error
Upvotes: 3